Fix for real email tests failing silently

This commit is contained in:
Rory Powell 2023-02-23 13:42:10 +00:00
parent d3a7286711
commit 2d993adec8
5 changed files with 26 additions and 75 deletions

View File

@ -1,3 +1,4 @@
jest.unmock("node-fetch")
import { TestConfiguration } from "../../../../tests"
import { EmailTemplatePurpose } from "../../../../constants"
const nodemailer = require("nodemailer")

View File

@ -13,6 +13,7 @@ export class EmailAPI extends TestAPI {
email: "test@test.com",
purpose,
tenantId: this.config.getTenantId(),
userId: this.config.user?._id!,
})
.set(this.config.defaultHeaders())
.expect("Content-Type", /json/)

View File

@ -55,8 +55,8 @@ export function smtpEthereal() {
host: "smtp.ethereal.email",
secure: false,
auth: {
user: "don.bahringer@ethereal.email",
pass: "yCKSH8rWyUPbnhGYk9",
user: "wyatt.zulauf29@ethereal.email",
pass: "tEwDtHBWWxusVWAPfa",
},
connectionTimeout: 1000, // must be less than the jest default of 5000
},

View File

@ -1,11 +1,11 @@
import env from "../environment"
import { EmailTemplatePurpose, TemplateType, Config } from "../constants"
import { EmailTemplatePurpose, TemplateType } from "../constants"
import { getTemplateByPurpose } from "../constants/templates"
import { getSettingsTemplateContext } from "./templates"
import { processString } from "@budibase/string-templates"
import { getResetPasswordCode, getInviteCode } from "./redis"
import { User, Database } from "@budibase/types"
import { tenancy, db as dbCore } from "@budibase/backend-core"
import { User, SMTPInnerConfig } from "@budibase/types"
import { configs } from "@budibase/backend-core"
const nodemailer = require("nodemailer")
type SendEmailOpts = {
@ -36,24 +36,24 @@ const FULL_EMAIL_PURPOSES = [
EmailTemplatePurpose.CUSTOM,
]
function createSMTPTransport(config: any) {
function createSMTPTransport(config?: SMTPInnerConfig) {
let options: any
let secure = config.secure
let secure = config?.secure
// default it if not specified
if (secure == null) {
secure = config.port === 465
secure = config?.port === 465
}
if (!TEST_MODE) {
options = {
port: config.port,
host: config.host,
port: config?.port,
host: config?.host,
secure: secure,
auth: config.auth,
auth: config?.auth,
}
options.tls = {
rejectUnauthorized: false,
}
if (config.connectionTimeout) {
if (config?.connectionTimeout) {
options.connectionTimeout = config.connectionTimeout
}
} else {
@ -134,57 +134,16 @@ async function buildEmail(
})
}
/**
* Utility function for finding most valid SMTP configuration.
* @param {object} db The CouchDB database which is to be looked up within.
* @param {string|null} workspaceId If using finer grain control of configs a workspace can be used.
* @param {boolean|null} automation Whether or not the configuration is being fetched for an email automation.
* @return {Promise<object|null>} returns the SMTP configuration if it exists
*/
async function getSmtpConfiguration(
db: Database,
workspaceId?: string,
automation?: boolean
) {
const params: any = {
type: Config.SMTP,
}
if (workspaceId) {
params.workspace = workspaceId
}
const customConfig = await dbCore.getScopedConfig(db, params)
if (customConfig) {
return customConfig
}
// Use an SMTP fallback configuration from env variables
if (!automation && env.SMTP_FALLBACK_ENABLED) {
return {
port: env.SMTP_PORT,
host: env.SMTP_HOST,
secure: false,
from: env.SMTP_FROM_ADDRESS,
auth: {
user: env.SMTP_USER,
pass: env.SMTP_PASSWORD,
},
}
}
}
/**
* Checks if a SMTP config exists based on passed in parameters.
* @return {Promise<boolean>} returns true if there is a configuration that can be used.
*/
export async function isEmailConfigured(workspaceId?: string) {
export async function isEmailConfigured() {
// when "testing" or smtp fallback is enabled simply return true
if (TEST_MODE || env.SMTP_FALLBACK_ENABLED) {
return true
}
const db = tenancy.getGlobalDB()
const config = await getSmtpConfiguration(db, workspaceId)
const config = await configs.getSMTPConfig()
return config != null
}
@ -202,22 +161,17 @@ export async function sendEmail(
purpose: EmailTemplatePurpose,
opts: SendEmailOpts
) {
const db = tenancy.getGlobalDB()
let config =
(await getSmtpConfiguration(db, opts?.workspaceId, opts?.automation)) || {}
if (Object.keys(config).length === 0 && !TEST_MODE) {
const config = await configs.getSMTPConfig(opts?.automation)
if (!config && !TEST_MODE) {
throw "Unable to find SMTP configuration."
}
const transport = createSMTPTransport(config)
// if there is a link code needed this will retrieve it
const code = await getLinkCode(purpose, email, opts.user, opts?.info)
let context
if (code) {
context = await getSettingsTemplateContext(purpose, code)
}
let context = await getSettingsTemplateContext(purpose, code)
let message: any = {
from: opts?.from || config.from,
from: opts?.from || config?.from,
html: await buildEmail(purpose, email, context, {
user: opts?.user,
contents: opts?.contents,
@ -231,9 +185,9 @@ export async function sendEmail(
bcc: opts?.bcc,
}
if (opts?.subject || config.subject) {
if (opts?.subject || config?.subject) {
message.subject = await processString(
opts?.subject || config.subject,
(opts?.subject || config?.subject) as string,
context
)
}

View File

@ -1,6 +1,5 @@
import { db as dbCore, tenancy } from "@budibase/backend-core"
import { tenancy, configs } from "@budibase/backend-core"
import {
Config,
InternalTemplateBinding,
LOGO_URL,
EmailTemplatePurpose,
@ -10,20 +9,16 @@ const BASE_COMPANY = "Budibase"
export async function getSettingsTemplateContext(
purpose: EmailTemplatePurpose,
code?: string
code?: string | null
) {
const db = tenancy.getGlobalDB()
// TODO: use more granular settings in the future if required
let settings =
(await dbCore.getScopedConfig(db, { type: Config.SETTINGS })) || {}
let settings = await configs.getSettingsConfig()
const URL = settings.platformUrl
const context: any = {
[InternalTemplateBinding.LOGO_URL]:
checkSlashesInUrl(`${URL}/${settings.logoUrl}`) || LOGO_URL,
[InternalTemplateBinding.PLATFORM_URL]: URL,
[InternalTemplateBinding.COMPANY]: settings.company || BASE_COMPANY,
[InternalTemplateBinding.DOCS_URL]:
settings.docsUrl || "https://docs.budibase.com/",
[InternalTemplateBinding.DOCS_URL]: "https://docs.budibase.com/",
[InternalTemplateBinding.LOGIN_URL]: checkSlashesInUrl(
tenancy.addTenantToUrl(`${URL}/login`)
),