Fixing test cases and bugs that they raised.
This commit is contained in:
parent
24012c2fba
commit
313302cae2
|
@ -82,13 +82,21 @@ exports.getGlobalDB = tenantId => {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a koa context this tries to find the correct tenant Global DB.
|
* Given a koa context this tries to extra what tenant is being accessed.
|
||||||
*/
|
*/
|
||||||
exports.getGlobalDBFromCtx = ctx => {
|
exports.getTenantIdFromCtx = ctx => {
|
||||||
const user = ctx.user || {}
|
const user = ctx.user || {}
|
||||||
const params = ctx.request.params || {}
|
const params = ctx.request.params || {}
|
||||||
const query = ctx.request.query || {}
|
const query = ctx.request.query || {}
|
||||||
return exports.getGlobalDB(user.tenantId || params.tenantId || query.tenantId)
|
return user.tenantId || params.tenantId || query.tenantId
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a koa context this tries to find the correct tenant Global DB.
|
||||||
|
*/
|
||||||
|
exports.getGlobalDBFromCtx = ctx => {
|
||||||
|
const tenantId = exports.getTenantIdFromCtx(ctx)
|
||||||
|
return exports.getGlobalDB(tenantId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -3,6 +3,7 @@ const appController = require("../../../controllers/application")
|
||||||
const CouchDB = require("../../../../db")
|
const CouchDB = require("../../../../db")
|
||||||
const { AppStatus } = require("../../../../db/utils")
|
const { AppStatus } = require("../../../../db/utils")
|
||||||
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
|
||||||
|
const { TENANT_ID } = require("../../../../tests/utilities/structures")
|
||||||
|
|
||||||
function Request(appId, params) {
|
function Request(appId, params) {
|
||||||
this.appId = appId
|
this.appId = appId
|
||||||
|
@ -16,8 +17,8 @@ exports.getAllTableRows = async config => {
|
||||||
return req.body
|
return req.body
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.clearAllApps = async () => {
|
exports.clearAllApps = async (tenantId = TENANT_ID) => {
|
||||||
const req = { query: { status: AppStatus.DEV } }
|
const req = { query: { status: AppStatus.DEV }, user: { tenantId } }
|
||||||
await appController.fetch(req)
|
await appController.fetch(req)
|
||||||
const apps = req.body
|
const apps = req.body
|
||||||
if (!apps || apps.length <= 0) {
|
if (!apps || apps.length <= 0) {
|
||||||
|
|
|
@ -10,20 +10,23 @@ const {
|
||||||
basicScreen,
|
basicScreen,
|
||||||
basicLayout,
|
basicLayout,
|
||||||
basicWebhook,
|
basicWebhook,
|
||||||
|
TENANT_ID,
|
||||||
} = require("./structures")
|
} = require("./structures")
|
||||||
const controllers = require("./controllers")
|
const controllers = require("./controllers")
|
||||||
const supertest = require("supertest")
|
const supertest = require("supertest")
|
||||||
const { cleanup } = require("../../utilities/fileSystem")
|
const { cleanup } = require("../../utilities/fileSystem")
|
||||||
const { Cookies } = require("@budibase/auth").constants
|
const { Cookies } = require("@budibase/auth").constants
|
||||||
const { jwt } = require("@budibase/auth").auth
|
const { jwt } = require("@budibase/auth").auth
|
||||||
|
const auth = require("@budibase/auth")
|
||||||
const { getGlobalDB } = require("@budibase/auth/db")
|
const { getGlobalDB } = require("@budibase/auth/db")
|
||||||
const { createASession } = require("@budibase/auth/sessions")
|
const { createASession } = require("@budibase/auth/sessions")
|
||||||
const { user: userCache } = require("@budibase/auth/cache")
|
const { user: userCache } = require("@budibase/auth/cache")
|
||||||
|
const CouchDB = require("../../db")
|
||||||
|
auth.init(CouchDB)
|
||||||
|
|
||||||
const GLOBAL_USER_ID = "us_uuid1"
|
const GLOBAL_USER_ID = "us_uuid1"
|
||||||
const EMAIL = "babs@babs.com"
|
const EMAIL = "babs@babs.com"
|
||||||
const PASSWORD = "babs_password"
|
const PASSWORD = "babs_password"
|
||||||
const TENANT_ID = "default"
|
|
||||||
|
|
||||||
class TestConfiguration {
|
class TestConfiguration {
|
||||||
constructor(openServer = true) {
|
constructor(openServer = true) {
|
||||||
|
@ -52,7 +55,7 @@ class TestConfiguration {
|
||||||
request.cookies = { set: () => {}, get: () => {} }
|
request.cookies = { set: () => {}, get: () => {} }
|
||||||
request.config = { jwtSecret: env.JWT_SECRET }
|
request.config = { jwtSecret: env.JWT_SECRET }
|
||||||
request.appId = this.appId
|
request.appId = this.appId
|
||||||
request.user = { appId: this.appId }
|
request.user = { appId: this.appId, tenantId: TENANT_ID }
|
||||||
request.query = {}
|
request.query = {}
|
||||||
request.request = {
|
request.request = {
|
||||||
body: config,
|
body: config,
|
||||||
|
@ -78,7 +81,7 @@ class TestConfiguration {
|
||||||
roles: roles || {},
|
roles: roles || {},
|
||||||
tenantId: TENANT_ID,
|
tenantId: TENANT_ID,
|
||||||
}
|
}
|
||||||
await createASession(id, "sessionid")
|
await createASession(id, { sessionId: "sessionid", tenantId: TENANT_ID })
|
||||||
if (builder) {
|
if (builder) {
|
||||||
user.builder = { global: true }
|
user.builder = { global: true }
|
||||||
}
|
}
|
||||||
|
@ -108,6 +111,7 @@ class TestConfiguration {
|
||||||
const auth = {
|
const auth = {
|
||||||
userId: GLOBAL_USER_ID,
|
userId: GLOBAL_USER_ID,
|
||||||
sessionId: "sessionid",
|
sessionId: "sessionid",
|
||||||
|
tenantId: TENANT_ID,
|
||||||
}
|
}
|
||||||
const app = {
|
const app = {
|
||||||
roleId: BUILTIN_ROLE_IDS.ADMIN,
|
roleId: BUILTIN_ROLE_IDS.ADMIN,
|
||||||
|
@ -334,11 +338,12 @@ class TestConfiguration {
|
||||||
if (!email || !password) {
|
if (!email || !password) {
|
||||||
await this.createUser()
|
await this.createUser()
|
||||||
}
|
}
|
||||||
await createASession(userId, "sessionid")
|
await createASession(userId, { sessionId: "sessionid", tenantId: TENANT_ID })
|
||||||
// have to fake this
|
// have to fake this
|
||||||
const auth = {
|
const auth = {
|
||||||
userId,
|
userId,
|
||||||
sessionId: "sessionid",
|
sessionId: "sessionid",
|
||||||
|
tenantId: TENANT_ID,
|
||||||
}
|
}
|
||||||
const app = {
|
const app = {
|
||||||
roleId: roleId,
|
roleId: roleId,
|
||||||
|
|
|
@ -4,6 +4,8 @@ const { createHomeScreen } = require("../../constants/screens")
|
||||||
const { EMPTY_LAYOUT } = require("../../constants/layouts")
|
const { EMPTY_LAYOUT } = require("../../constants/layouts")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
|
||||||
|
exports.TENANT_ID = "default"
|
||||||
|
|
||||||
exports.basicTable = () => {
|
exports.basicTable = () => {
|
||||||
return {
|
return {
|
||||||
name: "TestTable",
|
name: "TestTable",
|
||||||
|
|
|
@ -3,3 +3,4 @@ const env = require("../src/environment")
|
||||||
env._set("NODE_ENV", "jest")
|
env._set("NODE_ENV", "jest")
|
||||||
env._set("JWT_SECRET", "test-jwtsecret")
|
env._set("JWT_SECRET", "test-jwtsecret")
|
||||||
env._set("LOG_LEVEL", "silent")
|
env._set("LOG_LEVEL", "silent")
|
||||||
|
env._set("MULTI_TENANCY", true)
|
||||||
|
|
|
@ -74,6 +74,7 @@ exports.reset = async ctx => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
// don't throw any kind of error to the user, this might give away something
|
// don't throw any kind of error to the user, this might give away something
|
||||||
}
|
}
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
@ -88,7 +89,7 @@ exports.resetUpdate = async ctx => {
|
||||||
const { resetCode, password } = ctx.request.body
|
const { resetCode, password } = ctx.request.body
|
||||||
try {
|
try {
|
||||||
const userId = await checkResetPasswordCode(resetCode)
|
const userId = await checkResetPasswordCode(resetCode)
|
||||||
const db = new getGlobalDB(ctx.params.tenantId)
|
const db = getGlobalDB(ctx.params.tenantId)
|
||||||
const user = await db.get(userId)
|
const user = await db.get(userId)
|
||||||
user.password = await hash(password)
|
user.password = await hash(password)
|
||||||
await db.put(user)
|
await db.put(user)
|
||||||
|
|
|
@ -4,7 +4,7 @@ const {
|
||||||
TemplateBindings,
|
TemplateBindings,
|
||||||
GLOBAL_OWNER,
|
GLOBAL_OWNER,
|
||||||
} = require("../../../constants")
|
} = require("../../../constants")
|
||||||
const { getTemplates } = require("../../../constants/templates")
|
const { getTemplatesCtx } = require("../../../constants/templates")
|
||||||
|
|
||||||
exports.save = async ctx => {
|
exports.save = async ctx => {
|
||||||
const db = getGlobalDBFromCtx(ctx)
|
const db = getGlobalDBFromCtx(ctx)
|
||||||
|
@ -45,23 +45,23 @@ exports.definitions = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
exports.fetch = async ctx => {
|
||||||
ctx.body = await getTemplates(ctx)
|
ctx.body = await getTemplatesCtx(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchByType = async ctx => {
|
exports.fetchByType = async ctx => {
|
||||||
ctx.body = await getTemplates(ctx, {
|
ctx.body = await getTemplatesCtx(ctx, {
|
||||||
type: ctx.params.type,
|
type: ctx.params.type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchByOwner = async ctx => {
|
exports.fetchByOwner = async ctx => {
|
||||||
ctx.body = await getTemplates(ctx, {
|
ctx.body = await getTemplatesCtx(ctx, {
|
||||||
ownerId: ctx.params.ownerId,
|
ownerId: ctx.params.ownerId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async ctx => {
|
exports.find = async ctx => {
|
||||||
ctx.body = await getTemplates(ctx, {
|
ctx.body = await getTemplatesCtx(ctx, {
|
||||||
id: ctx.params.id,
|
id: ctx.params.id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,12 +265,16 @@ exports.find = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.invite = async ctx => {
|
exports.invite = async ctx => {
|
||||||
const { email, userInfo } = ctx.request.body
|
let { email, userInfo } = ctx.request.body
|
||||||
const tenantId = ctx.user.tenantId
|
const tenantId = ctx.user.tenantId
|
||||||
const existing = await getGlobalUserByEmail(email, tenantId)
|
const existing = await getGlobalUserByEmail(email, tenantId)
|
||||||
if (existing) {
|
if (existing) {
|
||||||
ctx.throw(400, "Email address already in use.")
|
ctx.throw(400, "Email address already in use.")
|
||||||
}
|
}
|
||||||
|
if (!userInfo) {
|
||||||
|
userInfo = {}
|
||||||
|
}
|
||||||
|
userInfo.tenantId = tenantId
|
||||||
await sendEmail(tenantId, email, EmailTemplatePurpose.INVITATION, {
|
await sendEmail(tenantId, email, EmailTemplatePurpose.INVITATION, {
|
||||||
subject: "{{ company }} platform invitation",
|
subject: "{{ company }} platform invitation",
|
||||||
info: userInfo,
|
info: userInfo,
|
||||||
|
@ -293,6 +297,9 @@ exports.inviteAccept = async ctx => {
|
||||||
email,
|
email,
|
||||||
...info,
|
...info,
|
||||||
}
|
}
|
||||||
|
ctx.user = {
|
||||||
|
tenantId: info.tenantId,
|
||||||
|
}
|
||||||
// this will flesh out the body response
|
// this will flesh out the body response
|
||||||
await exports.save(ctx)
|
await exports.save(ctx)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -36,8 +36,8 @@ describe("/api/global/auth", () => {
|
||||||
expect(sendMailMock).toHaveBeenCalled()
|
expect(sendMailMock).toHaveBeenCalled()
|
||||||
const emailCall = sendMailMock.mock.calls[0][0]
|
const emailCall = sendMailMock.mock.calls[0][0]
|
||||||
// after this URL there should be a code
|
// after this URL there should be a code
|
||||||
const parts = emailCall.html.split(`http://localhost:10000/builder/auth/${TENANT_ID}/reset?code=`)
|
const parts = emailCall.html.split(`http://localhost:10000/builder/auth/reset?code=`)
|
||||||
code = parts[1].split("\"")[0]
|
code = parts[1].split("\"")[0].split("&")[0]
|
||||||
expect(code).toBeDefined()
|
expect(code).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
const { EmailTemplatePurpose } = require("../../../constants")
|
const { EmailTemplatePurpose } = require("../../../constants")
|
||||||
|
const { TENANT_ID } = require("./utilities/structures")
|
||||||
|
|
||||||
// mock the email system
|
// mock the email system
|
||||||
const sendMailMock = jest.fn()
|
const sendMailMock = jest.fn()
|
||||||
|
@ -29,6 +30,7 @@ describe("/api/global/email", () => {
|
||||||
.send({
|
.send({
|
||||||
email: "test@test.com",
|
email: "test@test.com",
|
||||||
purpose: EmailTemplatePurpose.INVITATION,
|
purpose: EmailTemplatePurpose.INVITATION,
|
||||||
|
tenantId: TENANT_ID,
|
||||||
})
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
|
const { TENANT_ID } = require("./utilities/structures")
|
||||||
|
|
||||||
jest.mock("nodemailer")
|
jest.mock("nodemailer")
|
||||||
const sendMailMock = setup.emailMock()
|
const sendMailMock = setup.emailMock()
|
||||||
|
@ -31,7 +32,7 @@ describe("/api/global/users", () => {
|
||||||
const emailCall = sendMailMock.mock.calls[0][0]
|
const emailCall = sendMailMock.mock.calls[0][0]
|
||||||
// after this URL there should be a code
|
// after this URL there should be a code
|
||||||
const parts = emailCall.html.split("http://localhost:10000/builder/invite?code=")
|
const parts = emailCall.html.split("http://localhost:10000/builder/invite?code=")
|
||||||
code = parts[1].split("\"")[0]
|
code = parts[1].split("\"")[0].split("&")[0]
|
||||||
expect(code).toBeDefined()
|
expect(code).toBeDefined()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,10 @@ const { Configs, LOGO_URL } = require("../../../../constants")
|
||||||
const { getGlobalUserByEmail } = require("@budibase/auth").utils
|
const { getGlobalUserByEmail } = require("@budibase/auth").utils
|
||||||
const { createASession } = require("@budibase/auth/sessions")
|
const { createASession } = require("@budibase/auth/sessions")
|
||||||
const { newid } = require("../../../../../../auth/src/hashing")
|
const { newid } = require("../../../../../../auth/src/hashing")
|
||||||
|
const { TENANT_ID } = require("./structures")
|
||||||
const TENANT_ID = "default"
|
const auth = require("@budibase/auth")
|
||||||
|
const CouchDB = require("../../../../db")
|
||||||
|
auth.init(CouchDB)
|
||||||
|
|
||||||
class TestConfiguration {
|
class TestConfiguration {
|
||||||
constructor(openServer = true) {
|
constructor(openServer = true) {
|
||||||
|
@ -30,7 +32,7 @@ class TestConfiguration {
|
||||||
request.cookies = { set: () => {}, get: () => {} }
|
request.cookies = { set: () => {}, get: () => {} }
|
||||||
request.config = { jwtSecret: env.JWT_SECRET }
|
request.config = { jwtSecret: env.JWT_SECRET }
|
||||||
request.appId = this.appId
|
request.appId = this.appId
|
||||||
request.user = { appId: this.appId }
|
request.user = { appId: this.appId, tenantId: TENANT_ID }
|
||||||
request.query = {}
|
request.query = {}
|
||||||
request.request = {
|
request.request = {
|
||||||
body: config,
|
body: config,
|
||||||
|
@ -60,7 +62,7 @@ class TestConfiguration {
|
||||||
null,
|
null,
|
||||||
controllers.users.save
|
controllers.users.save
|
||||||
)
|
)
|
||||||
await createASession("us_uuid1", "sessionid")
|
await createASession("us_uuid1", { sessionId: "sessionid", tenantId: TENANT_ID })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +235,7 @@ class TestConfiguration {
|
||||||
{
|
{
|
||||||
email: "testuser@test.com",
|
email: "testuser@test.com",
|
||||||
password: "test@test.com",
|
password: "test@test.com",
|
||||||
|
tenantId: TENANT_ID,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
controllers.users.adminUser
|
controllers.users.adminUser
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
exports.TENANT_ID = "default"
|
|
@ -6,7 +6,7 @@ const {
|
||||||
GLOBAL_OWNER,
|
GLOBAL_OWNER,
|
||||||
} = require("../index")
|
} = require("../index")
|
||||||
const { join } = require("path")
|
const { join } = require("path")
|
||||||
const { getTemplateParams, getGlobalDBFromCtx } = require("@budibase/auth/db")
|
const { getTemplateParams, getTenantIdFromCtx, getGlobalDB } = require("@budibase/auth/db")
|
||||||
|
|
||||||
exports.EmailTemplates = {
|
exports.EmailTemplates = {
|
||||||
[EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile(
|
[EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile(
|
||||||
|
@ -48,8 +48,13 @@ exports.addBaseTemplates = (templates, type = null) => {
|
||||||
return templates
|
return templates
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTemplates = async (ctx, { ownerId, type, id } = {}) => {
|
exports.getTemplatesCtx = async (ctx, opts = {}) => {
|
||||||
const db = getGlobalDBFromCtx(ctx)
|
const tenantId = getTenantIdFromCtx(ctx)
|
||||||
|
return exports.getTemplates(tenantId, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getTemplates = async (tenantId, { ownerId, type, id} = {}) => {
|
||||||
|
const db = getGlobalDB(tenantId)
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getTemplateParams(ownerId || GLOBAL_OWNER, id, {
|
getTemplateParams(ownerId || GLOBAL_OWNER, id, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -66,7 +71,10 @@ exports.getTemplates = async (ctx, { ownerId, type, id } = {}) => {
|
||||||
return exports.addBaseTemplates(templates, type)
|
return exports.addBaseTemplates(templates, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTemplateByPurpose = async (ctx, type, purpose) => {
|
exports.getTemplateByPurpose = async ({ tenantId, ctx }, type, purpose) => {
|
||||||
const templates = await exports.getTemplates(ctx, { type })
|
if (!tenantId && ctx) {
|
||||||
|
tenantId = getTenantIdFromCtx(ctx)
|
||||||
|
}
|
||||||
|
const templates = await exports.getTemplates(tenantId, { type })
|
||||||
return templates.find(template => template.purpose === purpose)
|
return templates.find(template => template.purpose === purpose)
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ async function getLinkCode(purpose, email, user, info = null) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an email using handlebars and the templates found in the system (default or otherwise).
|
* Builds an email using handlebars and the templates found in the system (default or otherwise).
|
||||||
|
* @param {string} tenantId the ID of the tenant which is sending the email.
|
||||||
* @param {string} purpose the purpose of the email being built, e.g. invitation, password reset.
|
* @param {string} purpose the purpose of the email being built, e.g. invitation, password reset.
|
||||||
* @param {string} email the address which it is being sent to for contextual purposes.
|
* @param {string} email the address which it is being sent to for contextual purposes.
|
||||||
* @param {object} context the context which is being used for building the email (hbs context).
|
* @param {object} context the context which is being used for building the email (hbs context).
|
||||||
|
@ -67,14 +68,14 @@ async function getLinkCode(purpose, email, user, info = null) {
|
||||||
* @param {string|null} contents if using a custom template can supply contents for context.
|
* @param {string|null} contents if using a custom template can supply contents for context.
|
||||||
* @return {Promise<string>} returns the built email HTML if all provided parameters were valid.
|
* @return {Promise<string>} returns the built email HTML if all provided parameters were valid.
|
||||||
*/
|
*/
|
||||||
async function buildEmail(purpose, email, context, { user, contents } = {}) {
|
async function buildEmail(tenantId, purpose, email, context, { user, contents } = {}) {
|
||||||
// this isn't a full email
|
// this isn't a full email
|
||||||
if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) {
|
if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) {
|
||||||
throw `Unable to build an email of type ${purpose}`
|
throw `Unable to build an email of type ${purpose}`
|
||||||
}
|
}
|
||||||
let [base, body] = await Promise.all([
|
let [base, body] = await Promise.all([
|
||||||
getTemplateByPurpose(TYPE, EmailTemplatePurpose.BASE),
|
getTemplateByPurpose({ tenantId }, TYPE, EmailTemplatePurpose.BASE),
|
||||||
getTemplateByPurpose(TYPE, purpose),
|
getTemplateByPurpose({ tenantId }, TYPE, purpose),
|
||||||
])
|
])
|
||||||
if (!base || !body) {
|
if (!base || !body) {
|
||||||
throw "Unable to build email, missing base components"
|
throw "Unable to build email, missing base components"
|
||||||
|
@ -147,7 +148,7 @@ exports.sendEmail = async (
|
||||||
purpose,
|
purpose,
|
||||||
{ workspaceId, user, from, contents, subject, info } = {}
|
{ workspaceId, user, from, contents, subject, info } = {}
|
||||||
) => {
|
) => {
|
||||||
const db = new getGlobalDB(tenantId)
|
const db = getGlobalDB(tenantId)
|
||||||
let config = (await getSmtpConfiguration(db, workspaceId)) || {}
|
let config = (await getSmtpConfiguration(db, workspaceId)) || {}
|
||||||
if (Object.keys(config).length === 0 && !TEST_MODE) {
|
if (Object.keys(config).length === 0 && !TEST_MODE) {
|
||||||
throw "Unable to find SMTP configuration."
|
throw "Unable to find SMTP configuration."
|
||||||
|
@ -159,7 +160,7 @@ exports.sendEmail = async (
|
||||||
const message = {
|
const message = {
|
||||||
from: from || config.from,
|
from: from || config.from,
|
||||||
to: email,
|
to: email,
|
||||||
html: await buildEmail(purpose, email, context, { user, contents }),
|
html: await buildEmail(tenantId, purpose, email, context, { user, contents }),
|
||||||
}
|
}
|
||||||
if (subject || config.subject) {
|
if (subject || config.subject) {
|
||||||
message.subject = await processString(subject || config.subject, context)
|
message.subject = await processString(subject || config.subject, context)
|
||||||
|
|
|
@ -11,8 +11,16 @@ const env = require("../environment")
|
||||||
const LOCAL_URL = `http://localhost:${env.CLUSTER_PORT || 10000}`
|
const LOCAL_URL = `http://localhost:${env.CLUSTER_PORT || 10000}`
|
||||||
const BASE_COMPANY = "Budibase"
|
const BASE_COMPANY = "Budibase"
|
||||||
|
|
||||||
|
function addTenantToUrl(url, tenantId) {
|
||||||
|
if (env.MULTI_TENANCY) {
|
||||||
|
const char = url.indexOf("?") === -1 ? "?" : "&"
|
||||||
|
url += `${char}tenantId=${tenantId}`
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
exports.getSettingsTemplateContext = async (tenantId, purpose, code = null) => {
|
exports.getSettingsTemplateContext = async (tenantId, purpose, code = null) => {
|
||||||
const db = new getGlobalDB(tenantId)
|
const db = getGlobalDB(tenantId)
|
||||||
// TODO: use more granular settings in the future if required
|
// TODO: use more granular settings in the future if required
|
||||||
let settings = (await getScopedConfig(db, { type: Configs.SETTINGS })) || {}
|
let settings = (await getScopedConfig(db, { type: Configs.SETTINGS })) || {}
|
||||||
if (!settings || !settings.platformUrl) {
|
if (!settings || !settings.platformUrl) {
|
||||||
|
@ -26,7 +34,7 @@ exports.getSettingsTemplateContext = async (tenantId, purpose, code = null) => {
|
||||||
[InternalTemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
|
[InternalTemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
|
||||||
[InternalTemplateBindings.DOCS_URL]:
|
[InternalTemplateBindings.DOCS_URL]:
|
||||||
settings.docsUrl || "https://docs.budibase.com/",
|
settings.docsUrl || "https://docs.budibase.com/",
|
||||||
[InternalTemplateBindings.LOGIN_URL]: checkSlashesInUrl(`${URL}/login`),
|
[InternalTemplateBindings.LOGIN_URL]: checkSlashesInUrl(addTenantToUrl(`${URL}/login`, tenantId)),
|
||||||
[InternalTemplateBindings.CURRENT_DATE]: new Date().toISOString(),
|
[InternalTemplateBindings.CURRENT_DATE]: new Date().toISOString(),
|
||||||
[InternalTemplateBindings.CURRENT_YEAR]: new Date().getFullYear(),
|
[InternalTemplateBindings.CURRENT_YEAR]: new Date().getFullYear(),
|
||||||
}
|
}
|
||||||
|
@ -35,13 +43,13 @@ exports.getSettingsTemplateContext = async (tenantId, purpose, code = null) => {
|
||||||
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|
||||||
context[InternalTemplateBindings.RESET_CODE] = code
|
context[InternalTemplateBindings.RESET_CODE] = code
|
||||||
context[InternalTemplateBindings.RESET_URL] = checkSlashesInUrl(
|
context[InternalTemplateBindings.RESET_URL] = checkSlashesInUrl(
|
||||||
`${URL}/builder/auth/reset?code=${code}`
|
addTenantToUrl(`${URL}/builder/auth/reset?code=${code}`, tenantId)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case EmailTemplatePurpose.INVITATION:
|
case EmailTemplatePurpose.INVITATION:
|
||||||
context[InternalTemplateBindings.INVITE_CODE] = code
|
context[InternalTemplateBindings.INVITE_CODE] = code
|
||||||
context[InternalTemplateBindings.INVITE_URL] = checkSlashesInUrl(
|
context[InternalTemplateBindings.INVITE_URL] = checkSlashesInUrl(
|
||||||
`${URL}/builder/invite?code=${code}`
|
addTenantToUrl(`${URL}/builder/invite?code=${code}&tenantId=${tenantId}`, tenantId)
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue