diff --git a/packages/worker/src/api/routes/global/tests/realEmail.spec.ts b/packages/worker/src/api/routes/global/tests/realEmail.spec.ts index 1c180be75d..8ad7363c85 100644 --- a/packages/worker/src/api/routes/global/tests/realEmail.spec.ts +++ b/packages/worker/src/api/routes/global/tests/realEmail.spec.ts @@ -1,3 +1,4 @@ +jest.unmock("node-fetch") import { TestConfiguration } from "../../../../tests" import { EmailTemplatePurpose } from "../../../../constants" const nodemailer = require("nodemailer") diff --git a/packages/worker/src/tests/api/email.ts b/packages/worker/src/tests/api/email.ts index ba7c7dbec0..fd3c622cfa 100644 --- a/packages/worker/src/tests/api/email.ts +++ b/packages/worker/src/tests/api/email.ts @@ -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/) diff --git a/packages/worker/src/tests/structures/configs.ts b/packages/worker/src/tests/structures/configs.ts index 2c76f271c4..9b5b29f652 100644 --- a/packages/worker/src/tests/structures/configs.ts +++ b/packages/worker/src/tests/structures/configs.ts @@ -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 }, diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index 66e860edcb..69861684eb 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -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} 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} 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 ) } diff --git a/packages/worker/src/utilities/templates.ts b/packages/worker/src/utilities/templates.ts index ede95dbe4a..1597325c7c 100644 --- a/packages/worker/src/utilities/templates.ts +++ b/packages/worker/src/utilities/templates.ts @@ -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`) ),