SMTP and template management E2E

This commit is contained in:
Martin McKeaveney 2021-05-06 18:02:44 +01:00
parent e8774eebab
commit cb2b1037ba
5 changed files with 277 additions and 81 deletions

View File

@ -12,55 +12,47 @@
let modal
</script>
{#if $auth}
{#if $auth.user}
<div class="root">
<div class="ui-nav">
<div class="home-logo">
<img src={Logo} alt="Budibase icon" />
</div>
<div class="nav-section">
<div class="nav-top">
<Navigation>
<Item href="/builder/" icon="Apps" selected>Apps</Item>
<Item external href="https://portal.budi.live/" icon="Servers">
Hosting
</Item>
<Item external href="https://docs.budibase.com/" icon="Book">
Documentation
</Item>
<Item
external
href="https://github.com/Budibase/budibase/discussions"
icon="PeopleGroup"
>
Community
</Item>
<Item
external
href="https://github.com/Budibase/budibase/issues/new/choose"
icon="Bug"
>
Raise an issue
</Item>
</Navigation>
</div>
<div class="nav-bottom">
<BuilderSettingsButton />
<LogoutButton />
</div>
</div>
<div class="root">
<div class="ui-nav">
<div class="home-logo">
<img src={Logo} alt="Budibase icon" />
</div>
<div class="nav-section">
<div class="nav-top">
<Navigation>
<Item href="/builder/" icon="Apps" selected>Apps</Item>
<Item external href="https://portal.budi.live/" icon="Servers">
Hosting
</Item>
<Item external href="https://docs.budibase.com/" icon="Book">
Documentation
</Item>
<Item
external
href="https://github.com/Budibase/budibase/discussions"
icon="PeopleGroup"
>
Community
</Item>
<Item
external
href="https://github.com/Budibase/budibase/issues/new/choose"
icon="Bug"
>
Raise an issue
</Item>
</Navigation>
</div>
<div class="main">
<slot />
<div class="nav-bottom">
<BuilderSettingsButton />
<LogoutButton />
</div>
</div>
{:else}
<section class="login">
<LoginForm />
</section>
{/if}
{/if}
</div>
<div class="main">
<slot />
</div>
</div>
<style>
.root {

View File

@ -14,8 +14,10 @@
SideNavigation as Navigation,
SideNavigationItem as Item,
} from "@budibase/bbui"
import LoginForm from "components/login/LoginForm.svelte"
import api from "builderStore/api"
import ConfigChecklist from "components/common/ConfigChecklist.svelte"
import { auth } from "stores/backend"
import { organisation, admin } from "stores/portal"
organisation.init()
@ -47,43 +49,52 @@
]
</script>
<div class="container">
<div class="nav">
<Layout paddingX="L" paddingY="L">
<div class="branding">
<div class="name">
<img
src={$organisation?.logoUrl || "https://i.imgur.com/ZKyklgF.png"}
alt="Logotype"
/>
<span>{$organisation?.company || "Budibase"}</span>
{#if $auth}
{#if $auth.user}
<div class="container">
<div class="nav">
<Layout paddingX="L" paddingY="L">
<div class="branding">
<div class="name">
<img
src={$organisation?.logoUrl ||
"https://i.imgur.com/ZKyklgF.png"}
alt="Logotype"
/>
<span>{$organisation?.company || "Budibase"}</span>
</div>
<div class="onboarding">
<ConfigChecklist />
</div>
</div>
<div class="menu">
<Navigation>
{#each menu as { title, href, heading }}
<Item selected={$isActive(href)} {href} {heading}>{title}</Item>
{/each}
</Navigation>
</div>
</Layout>
</div>
<div class="main">
<div class="toolbar">
<Search placeholder="Global search" />
<div class="avatar">
<Avatar size="M" name="John Doe" />
<Icon size="XL" name="ChevronDown" />
</div>
</div>
<div class="onboarding">
<ConfigChecklist />
<div class="content">
<slot />
</div>
</div>
<div class="menu">
<Navigation>
{#each menu as { title, href, heading }}
<Item selected={$isActive(href)} {href} {heading}>{title}</Item>
{/each}
</Navigation>
</div>
</Layout>
</div>
<div class="main">
<div class="toolbar">
<Search placeholder="Global search" />
<div class="avatar">
<Avatar size="M" name="John Doe" />
<Icon size="XL" name="ChevronDown" />
</div>
</div>
<div>
<slot />
</div>
</div>
</div>
{:else}
<section class="login">
<LoginForm />
</section>
{/if}
{/if}
<style>
.container {

View File

@ -0,0 +1,193 @@
<script>
import {
Button,
Heading,
Divider,
Label,
notifications,
Layout,
Input,
TextArea,
Body,
Page,
Select,
} from "@budibase/bbui"
import { onMount } from "svelte"
import api from "builderStore/api"
const ConfigTypes = {
SMTP: "smtp",
}
let smtpConfig
let templateIdx = 0
let templateDefinition
let templates = []
$: templateTypes = templates.map((template, idx) => ({
label: template.purpose,
value: idx,
}))
$: selectedTemplate = templates[templateIdx]
async function saveSmtp() {
try {
// Save your SMTP config
const response = await api.post(`/api/admin/configs`, smtpConfig)
const json = await response.json()
if (response.status !== 200) throw new Error(json.message)
smtpConfig._rev = json._rev
smtpConfig._id = json._id
notifications.success(`Settings saved.`)
} catch (err) {
notifications.error(`Failed to save email settings. ${err}`)
}
}
async function saveTemplate() {
try {
// Save your SMTP config
const response = await api.post(`/api/admin/template`, selectedTemplate)
const json = await response.json()
if (response.status !== 200) throw new Error(json.message)
selectedTemplate._rev = json._rev
selectedTemplate._id = json._id
notifications.success(`Template saved.`)
} catch (err) {
notifications.error(`Failed to update template settings. ${err}`)
}
}
async function fetchSmtp() {
// fetch the configs for smtp
const smtpResponse = await api.get(`/api/admin/configs/${ConfigTypes.SMTP}`)
const smtpDoc = await smtpResponse.json()
if (!smtpDoc._id) {
smtpConfig = {
type: ConfigTypes.SMTP,
config: {
auth: {
type: "login",
},
},
}
} else {
smtpConfig = smtpDoc
}
}
async function fetchTemplates() {
// fetch the email template definitions
const templatesResponse = await api.get(`/api/admin/template/definitions`)
const templateDefDoc = await templatesResponse.json()
// fetch the email templates themselves
const emailTemplatesResponse = await api.get(`/api/admin/template/email`)
const emailTemplates = await emailTemplatesResponse.json()
templateDefinition = templateDefDoc
templates = emailTemplates
}
onMount(async () => {
await fetchSmtp()
await fetchTemplates()
})
</script>
<Page>
<header>
<Heading size="M">Email</Heading>
<Body size="S">
Sending email is not required, but highly recommended for processes such
as password recovery. To setup automated auth emails, simply add the
values below and click activate.
</Body>
</header>
<Divider />
{#if smtpConfig}
<div class="config-form">
<Heading size="S">SMTP</Heading>
<Body size="S">
To allow your app to benefit from automated auth emails, add your SMTP
details below.
</Body>
<Layout gap="S">
<Heading size="S">
<span />
</Heading>
<div class="form-row">
<Label>Host</Label>
<Input bind:value={smtpConfig.config.host} />
</div>
<div class="form-row">
<Label>Port</Label>
<Input type="number" bind:value={smtpConfig.config.port} />
</div>
<div class="form-row">
<Label>User</Label>
<Input bind:value={smtpConfig.config.auth.user} />
</div>
<div class="form-row">
<Label>Password</Label>
<Input type="password" bind:value={smtpConfig.config.auth.pass} />
</div>
<div class="form-row">
<Label>From email address</Label>
<Input type="email" bind:value={smtpConfig.config.from} />
</div>
<Button cta on:click={saveSmtp}>Save</Button>
</Layout>
</div>
<Divider />
<div class="config-form">
<Heading size="S">Templates</Heading>
<Body size="S">
Budibase comes out of the box with ready-made email templates to help
with user onboarding. Please refrain from changing the links.
</Body>
<div class="template-controls">
<Select bind:value={templateIdx} options={templateTypes} />
<Button cta on:click={saveTemplate}>Save</Button>
</div>
{#if selectedTemplate}
<TextArea bind:value={selectedTemplate.contents} />
{/if}
</div>
{/if}
</Page>
<style>
.config-form {
margin-top: 42px;
margin-bottom: 42px;
}
.form-row {
display: grid;
grid-template-columns: 20% 1fr;
grid-gap: var(--spacing-l);
}
span {
display: flex;
align-items: center;
gap: var(--spacing-s);
}
header {
margin-bottom: 42px;
}
.template-controls {
display: grid;
grid-template-columns: 80% 1fr;
grid-gap: var(--spacing-xl);
margin-bottom: var(--spacing-xl);
}
</style>

View File

@ -1,5 +1,5 @@
const { generateTemplateID, StaticDatabases } = require("@budibase/auth").db
const { CouchDB } = require("../../../db")
const CouchDB = require("../../../db")
const {
TemplateMetadata,
TemplateBindings,

View File

@ -17,7 +17,7 @@ function smtpValidation() {
auth: Joi.object({
type: Joi.string().valid("login", "oauth2", null),
user: Joi.string().required(),
pass: Joi.string().valid("", null),
pass: Joi.string().allow("", null),
}).optional(),
}).unknown(true)
}