mirror of https://github.com/requarks/wiki
parent
78ae137f48
commit
2b98a5f27a
@ -0,0 +1,206 @@
|
|||||||
|
<template lang='pug'>
|
||||||
|
v-container(fluid, grid-list-lg)
|
||||||
|
v-layout(row wrap)
|
||||||
|
v-flex(xs12)
|
||||||
|
.admin-header
|
||||||
|
img(src='/svg/icon-new-post.svg', alt='Mail', style='width: 80px;')
|
||||||
|
.admin-header-title
|
||||||
|
.headline.primary--text {{ $t('admin:mail.title') }}
|
||||||
|
.subheading.grey--text {{ $t('admin:mail.subtitle') }}
|
||||||
|
v-spacer
|
||||||
|
v-btn(color='success', depressed, @click='save', large)
|
||||||
|
v-icon(left) check
|
||||||
|
span {{$t('common:actions.apply')}}
|
||||||
|
v-form.pt-3
|
||||||
|
v-layout(row wrap)
|
||||||
|
v-flex(lg6 xs12)
|
||||||
|
v-form
|
||||||
|
v-card.wiki-form
|
||||||
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
|
v-toolbar-title
|
||||||
|
.subheading {{ $t('admin:mail.configuration') }}
|
||||||
|
v-subheader Sender
|
||||||
|
.px-3.pb-3
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.senderName'
|
||||||
|
label='Sender Name'
|
||||||
|
required
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='person'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.senderEmail'
|
||||||
|
label='Sender Email'
|
||||||
|
required
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='email'
|
||||||
|
)
|
||||||
|
v-divider
|
||||||
|
v-subheader SMTP Settings
|
||||||
|
.px-3.pb-3
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.host'
|
||||||
|
label='Host'
|
||||||
|
required
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='memory'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.port'
|
||||||
|
label='Port'
|
||||||
|
required
|
||||||
|
prepend-icon='router'
|
||||||
|
persistent-hint
|
||||||
|
hint='Usually 465 (recommended), 587 or 25.'
|
||||||
|
style='max-width: 300px;'
|
||||||
|
)
|
||||||
|
v-switch(
|
||||||
|
v-model='config.secure'
|
||||||
|
label='Secure (TLS)'
|
||||||
|
color='primary'
|
||||||
|
persistent-hint
|
||||||
|
hint='Should be enabled when using port 465, otherwise turned off (587 or 25).'
|
||||||
|
prepend-icon='vpn_lock'
|
||||||
|
)
|
||||||
|
v-text-field.mt-3(
|
||||||
|
outline
|
||||||
|
v-model='config.user'
|
||||||
|
label='Username'
|
||||||
|
required
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='lock_outline'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.pass'
|
||||||
|
label='Password'
|
||||||
|
required
|
||||||
|
prepend-icon='lock'
|
||||||
|
type='password'
|
||||||
|
)
|
||||||
|
|
||||||
|
v-flex(lg6 xs12)
|
||||||
|
v-card.wiki-form
|
||||||
|
v-form
|
||||||
|
v-toolbar(color='primary', dark, dense, flat)
|
||||||
|
v-toolbar-title
|
||||||
|
.subheading {{ $t('admin:mail.dkim') }}
|
||||||
|
.pa-3
|
||||||
|
.body-2.grey--text.text--darken-2 DKIM (DomainKeys Identified Mail) provides a layer of security on all emails sent from Wiki.js by providing the means for recipients to validate the domain name and ensure the message authenticity.
|
||||||
|
v-switch(
|
||||||
|
v-model='config.useDKIM'
|
||||||
|
label='Use DKIM'
|
||||||
|
color='primary'
|
||||||
|
prepend-icon='vpn_key'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.dkimDomainName'
|
||||||
|
label='Domain Name'
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='vpn_key'
|
||||||
|
:disabled='!config.useDKIM'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.dkimKeySelector'
|
||||||
|
label='Key Selector'
|
||||||
|
:counter='255'
|
||||||
|
prepend-icon='vpn_key'
|
||||||
|
:disabled='!config.useDKIM'
|
||||||
|
)
|
||||||
|
v-text-field(
|
||||||
|
outline
|
||||||
|
v-model='config.dkimPrivateKey'
|
||||||
|
label='Private Key'
|
||||||
|
prepend-icon='vpn_key'
|
||||||
|
persistent-hint
|
||||||
|
hint='Private key for the selector in PEM format'
|
||||||
|
:disabled='!config.useDKIM'
|
||||||
|
)
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { get, sync } from 'vuex-pathify'
|
||||||
|
import mailConfigQuery from 'gql/admin/mail/mail-query-config.gql'
|
||||||
|
import mailUpdateConfigMutation from 'gql/admin/mail/mail-mutation-save-config.gql'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
config: {
|
||||||
|
senderName: '',
|
||||||
|
senderEmail: '',
|
||||||
|
host: '',
|
||||||
|
port: 0,
|
||||||
|
secure: false,
|
||||||
|
user: '',
|
||||||
|
pass: '',
|
||||||
|
useDKIM: false,
|
||||||
|
dkimDomainName: '',
|
||||||
|
dkimKeySelector: '',
|
||||||
|
dkimPrivateKey: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
darkMode: get('site/dark')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async save () {
|
||||||
|
try {
|
||||||
|
await this.$apollo.mutate({
|
||||||
|
mutation: mailUpdateConfigMutation,
|
||||||
|
variables: {
|
||||||
|
senderName: this.config.senderName || '',
|
||||||
|
senderEmail: this.config.senderEmail || '',
|
||||||
|
host: this.config.host || '',
|
||||||
|
port: _.toSafeInteger(this.config.port) || 0,
|
||||||
|
secure: this.config.secure || false,
|
||||||
|
user: this.config.user || '',
|
||||||
|
pass: this.config.pass || '',
|
||||||
|
useDKIM: this.config.useDKIM || false,
|
||||||
|
dkimDomainName: this.config.dkimDomainName || '',
|
||||||
|
dkimKeySelector: this.config.dkimKeySelector || '',
|
||||||
|
dkimPrivateKey: this.config.dkimPrivateKey || ''
|
||||||
|
},
|
||||||
|
watchLoading (isLoading) {
|
||||||
|
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-mail-update')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$store.commit('showNotification', {
|
||||||
|
style: 'success',
|
||||||
|
message: 'Configuration saved successfully.',
|
||||||
|
icon: 'check'
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
this.$store.commit('showNotification', {
|
||||||
|
style: 'red',
|
||||||
|
message: err.message,
|
||||||
|
icon: 'warning'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
config: {
|
||||||
|
query: mailConfigQuery,
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
update: (data) => _.cloneDeep(data.mail.config),
|
||||||
|
watchLoading (isLoading) {
|
||||||
|
this.$store.commit(`loading${isLoading ? 'Start' : 'Stop'}`, 'admin-mail-refresh')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang='scss'>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,36 @@
|
|||||||
|
mutation (
|
||||||
|
$senderName: String!,
|
||||||
|
$senderEmail: String!,
|
||||||
|
$host: String!,
|
||||||
|
$port: Int!,
|
||||||
|
$secure: Boolean!,
|
||||||
|
$user: String!,
|
||||||
|
$pass: String!,
|
||||||
|
$useDKIM: Boolean!,
|
||||||
|
$dkimDomainName: String!,
|
||||||
|
$dkimKeySelector: String!,
|
||||||
|
$dkimPrivateKey: String!
|
||||||
|
) {
|
||||||
|
mail {
|
||||||
|
updateConfig(
|
||||||
|
senderName: $senderName,
|
||||||
|
senderEmail: $senderEmail,
|
||||||
|
host: $host,
|
||||||
|
port: $port,
|
||||||
|
secure: $secure,
|
||||||
|
user: $user,
|
||||||
|
pass: $pass,
|
||||||
|
useDKIM: $useDKIM,
|
||||||
|
dkimDomainName: $dkimDomainName,
|
||||||
|
dkimKeySelector: $dkimKeySelector,
|
||||||
|
dkimPrivateKey: $dkimPrivateKey
|
||||||
|
) {
|
||||||
|
responseResult {
|
||||||
|
succeeded
|
||||||
|
errorCode
|
||||||
|
slug
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
mail {
|
||||||
|
config {
|
||||||
|
senderName
|
||||||
|
senderEmail
|
||||||
|
host
|
||||||
|
port
|
||||||
|
secure
|
||||||
|
user
|
||||||
|
pass
|
||||||
|
useDKIM
|
||||||
|
dkimDomainName
|
||||||
|
dkimKeySelector
|
||||||
|
dkimPrivateKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,74 @@
|
|||||||
|
const nodemailer = require('nodemailer')
|
||||||
|
const _ = require('lodash')
|
||||||
|
const fs = require('fs-extra')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
transport: null,
|
||||||
|
templates: {},
|
||||||
|
init() {
|
||||||
|
if (_.get(WIKI.config, 'mail.host', '').length > 2) {
|
||||||
|
let conf = {
|
||||||
|
host: WIKI.config.mail.host,
|
||||||
|
port: WIKI.config.mail.port,
|
||||||
|
secure: WIKI.config.mail.secure
|
||||||
|
}
|
||||||
|
if (_.get(WIKI.config, 'mail.user', '').length > 1) {
|
||||||
|
conf = {
|
||||||
|
...conf,
|
||||||
|
auth: {
|
||||||
|
user: WIKI.config.mail.user,
|
||||||
|
pass: WIKI.config.mail.pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_.get(WIKI.config, 'mail.useDKIM', false)) {
|
||||||
|
conf = {
|
||||||
|
...conf,
|
||||||
|
dkim: {
|
||||||
|
domainName: WIKI.config.mail.dkimDomainName,
|
||||||
|
keySelector: WIKI.config.mail.dkimKeySelector,
|
||||||
|
privateKey: WIKI.config.mail.dkimPrivateKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.transport = nodemailer.createTransport(conf)
|
||||||
|
} else {
|
||||||
|
WIKI.logger.warn('Mail is not setup! Please set the configuration in the administration area!')
|
||||||
|
this.transport = null
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
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.MailNotSetup()
|
||||||
|
}
|
||||||
|
await this.loadTemplate(opts.template)
|
||||||
|
return this.transport.sendMail({
|
||||||
|
from: 'noreply@requarks.io',
|
||||||
|
to: opts.to,
|
||||||
|
subject: `${opts.subject} - ${WIKI.config.title}`,
|
||||||
|
text: opts.text,
|
||||||
|
html: _.get(this.templates, opts.template)({
|
||||||
|
logo: '',
|
||||||
|
siteTitle: WIKI.config.title,
|
||||||
|
copyright: 'Powered by Wiki.js',
|
||||||
|
...opts.data
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async loadTemplate(key) {
|
||||||
|
if (_.has(this.templates, key)) { return }
|
||||||
|
const keyKebab = _.kebabCase(key)
|
||||||
|
try {
|
||||||
|
const rawTmpl = await fs.readFile(path.join(WIKI.SERVERPATH, `templates/${keyKebab}.html`), 'utf8')
|
||||||
|
_.set(this.templates, key, _.template(rawTmpl))
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
throw new WIKI.Error.MailTemplateFailed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
const _ = require('lodash')
|
||||||
|
const graphHelper = require('../../helpers/graph')
|
||||||
|
|
||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Query: {
|
||||||
|
async mail() { return {} }
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
async mail() { return {} }
|
||||||
|
},
|
||||||
|
MailQuery: {
|
||||||
|
async config(obj, args, context, info) {
|
||||||
|
return WIKI.config.mail
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MailMutation: {
|
||||||
|
async updateConfig(obj, args, context) {
|
||||||
|
try {
|
||||||
|
WIKI.config.mail = {
|
||||||
|
senderName: args.senderName,
|
||||||
|
senderEmail: args.senderEmail,
|
||||||
|
host: args.host,
|
||||||
|
port: args.port,
|
||||||
|
secure: args.secure,
|
||||||
|
user: args.user,
|
||||||
|
pass: args.pass,
|
||||||
|
useDKIM: args.useDKIM,
|
||||||
|
dkimDomainName: args.dkimDomainName,
|
||||||
|
dkimKeySelector: args.dkimKeySelector,
|
||||||
|
dkimPrivateKey: args.dkimPrivateKey,
|
||||||
|
}
|
||||||
|
await WIKI.configSvc.saveToDb(['mail'])
|
||||||
|
|
||||||
|
WIKI.mail.init()
|
||||||
|
|
||||||
|
return {
|
||||||
|
responseResult: graphHelper.generateSuccess('Mail configuration updated successfully')
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return graphHelper.generateError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
# ===============================================
|
||||||
|
# MAIL
|
||||||
|
# ===============================================
|
||||||
|
|
||||||
|
extend type Query {
|
||||||
|
mail: MailQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Mutation {
|
||||||
|
mail: MailMutation
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# QUERIES
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type MailQuery {
|
||||||
|
config: MailConfig @auth(requires: ["manage:system"])
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# MUTATIONS
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type MailMutation {
|
||||||
|
updateConfig(
|
||||||
|
senderName: String!
|
||||||
|
senderEmail: String!
|
||||||
|
host: String!
|
||||||
|
port: Int!
|
||||||
|
secure: Boolean!
|
||||||
|
user: String!
|
||||||
|
pass: String!
|
||||||
|
useDKIM: Boolean!
|
||||||
|
dkimDomainName: String!
|
||||||
|
dkimKeySelector: String!
|
||||||
|
dkimPrivateKey: String!
|
||||||
|
): DefaultResponse @auth(requires: ["manage:system"])
|
||||||
|
}
|
||||||
|
|
||||||
|
# -----------------------------------------------
|
||||||
|
# TYPES
|
||||||
|
# -----------------------------------------------
|
||||||
|
|
||||||
|
type MailConfig {
|
||||||
|
senderName: String!
|
||||||
|
senderEmail: String!
|
||||||
|
host: String!
|
||||||
|
port: Int!
|
||||||
|
secure: Boolean!
|
||||||
|
user: String!
|
||||||
|
pass: String!
|
||||||
|
useDKIM: Boolean!
|
||||||
|
dkimDomainName: String!
|
||||||
|
dkimKeySelector: String!
|
||||||
|
dkimPrivateKey: String!
|
||||||
|
}
|
Loading…
Reference in new issue