Major update, fixing email test case.

This commit is contained in:
mike12345567 2021-04-23 18:54:12 +01:00
parent 0dd46d12fa
commit 48c1b4b1fe
15 changed files with 67 additions and 33 deletions

View File

@ -28,6 +28,12 @@ async function buildEmail(purpose, email, user) {
getTemplateByPurpose(TYPE, EmailTemplatePurpose.STYLES), getTemplateByPurpose(TYPE, EmailTemplatePurpose.STYLES),
getTemplateByPurpose(TYPE, purpose), getTemplateByPurpose(TYPE, purpose),
]) ])
if (!base || !styles || !body) {
throw "Unable to build email, missing base components"
}
base = base.contents
styles = styles.contents
body = body.contents
// TODO: need to extend the context as much as possible // TODO: need to extend the context as much as possible
const context = { const context = {
@ -59,6 +65,9 @@ exports.sendEmail = async ctx => {
user = db.get(userId) user = db.get(userId)
} }
const config = await determineScopedConfig(db, params) const config = await determineScopedConfig(db, params)
if (!config) {
ctx.throw(400, "Unable to find SMTP configuration")
}
const transport = createSMTPTransport(config) const transport = createSMTPTransport(config)
const message = { const message = {
from: config.from, from: config.from,

View File

@ -1,10 +1,13 @@
const { generateTemplateID, StaticDatabases } = require("@budibase/auth").db const { generateTemplateID, StaticDatabases } = require("@budibase/auth").db
const { CouchDB } = require("../../../db") const { CouchDB } = require("../../../db")
const { TemplateMetadata, TemplateBindings } = require("../../../constants") const {
TemplateMetadata,
TemplateBindings,
GLOBAL_OWNER,
} = require("../../../constants")
const { getTemplates } = require("../../../constants/templates") const { getTemplates } = require("../../../constants/templates")
const GLOBAL_DB = StaticDatabases.GLOBAL.name const GLOBAL_DB = StaticDatabases.GLOBAL.name
const GLOBAL_OWNER = "global"
exports.save = async ctx => { exports.save = async ctx => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)

View File

@ -11,7 +11,7 @@ const FIRST_USER_EMAIL = "test@test.com"
const FIRST_USER_PASSWORD = "test" const FIRST_USER_PASSWORD = "test"
const GLOBAL_DB = StaticDatabases.GLOBAL.name const GLOBAL_DB = StaticDatabases.GLOBAL.name
exports.userSave = async ctx => { exports.save = async ctx => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const { email, password, _id } = ctx.request.body const { email, password, _id } = ctx.request.body
@ -69,10 +69,10 @@ exports.firstUser = async ctx => {
global: true, global: true,
}, },
} }
await exports.userSave(ctx) await exports.save(ctx)
} }
exports.userDelete = async ctx => { exports.destroy = async ctx => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const dbUser = await db.get(ctx.params.id) const dbUser = await db.get(ctx.params.id)
await db.remove(dbUser._id, dbUser._rev) await db.remove(dbUser._id, dbUser._rev)
@ -82,7 +82,7 @@ exports.userDelete = async ctx => {
} }
// called internally by app server user fetch // called internally by app server user fetch
exports.userFetch = async ctx => { exports.fetch = async ctx => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const response = await db.allDocs( const response = await db.allDocs(
getGlobalUserParams(null, { getGlobalUserParams(null, {
@ -100,7 +100,7 @@ exports.userFetch = async ctx => {
} }
// called internally by app server user find // called internally by app server user find
exports.userFind = async ctx => { exports.find = async ctx => {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
let user let user
try { try {

View File

@ -25,7 +25,7 @@ function smtpValidation() {
function settingValidation() { function settingValidation() {
// prettier-ignore // prettier-ignore
return Joi.object({ return Joi.object({
url: Joi.string().valid("", null), platformUrl: Joi.string().valid("", null),
logoUrl: Joi.string().valid("", null), logoUrl: Joi.string().valid("", null),
company: Joi.string().required(), company: Joi.string().required(),
}).unknown(true) }).unknown(true)

View File

@ -25,10 +25,10 @@ function buildUserSaveValidation() {
} }
router router
.post("/api/admin/users", buildUserSaveValidation(), controller.userSave) .post("/api/admin/users", buildUserSaveValidation(), controller.save)
.get("/api/admin/users", controller.userFetch) .get("/api/admin/users", controller.fetch)
.post("/api/admin/users/first", controller.firstUser) .post("/api/admin/users/first", controller.firstUser)
.delete("/api/admin/users/:id", controller.userDelete) .delete("/api/admin/users/:id", controller.destroy)
.get("/api/admin/users/:id", controller.userFind) .get("/api/admin/users/:id", controller.find)
module.exports = router module.exports = router

View File

@ -5,12 +5,19 @@ const { EmailTemplatePurpose } = require("../../../constants")
const sendMailMock = jest.fn() const sendMailMock = jest.fn()
jest.mock("nodemailer") jest.mock("nodemailer")
const nodemailer = require("nodemailer") const nodemailer = require("nodemailer")
nodemailer.createTransport.mockReturnValue({"sendMail": sendMailMock}); nodemailer.createTransport.mockReturnValue({
sendMail: sendMailMock,
verify: jest.fn()
})
describe("/api/admin/email", () => { describe("/api/admin/email", () => {
let request = setup.getRequest() let request = setup.getRequest()
let config = setup.getConfig() let config = setup.getConfig()
beforeAll(async () => {
await config.init()
})
afterAll(setup.afterAll) afterAll(setup.afterAll)
it("should be able to send an email (with mocking)", async () => { it("should be able to send an email (with mocking)", async () => {
@ -26,5 +33,10 @@ describe("/api/admin/email", () => {
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
expect(res.body.message).toBeDefined()
expect(sendMailMock).toHaveBeenCalled()
const emailCall = sendMailMock.mock.calls[0][0]
expect(emailCall.subject).toBe("Hello!")
expect(emailCall.html).not.toContain("Invalid Binding")
}) })
}) })

View File

@ -39,6 +39,8 @@ class TestConfiguration {
async init() { async init() {
// create a test user // create a test user
await this._req({ await this._req({
email: "test@test.com",
password: "test",
_id: "us_uuid1", _id: "us_uuid1",
builder: { builder: {
global: true, global: true,
@ -64,7 +66,7 @@ class TestConfiguration {
await this._req({ await this._req({
type: Configs.SETTINGS, type: Configs.SETTINGS,
config: { config: {
url: "http://localhost:10000", platformUrl: "http://localhost:10000",
logoUrl: "http://localhost:10000/logo", logoUrl: "http://localhost:10000/logo",
company: "TestCompany", company: "TestCompany",
} }
@ -78,7 +80,7 @@ class TestConfiguration {
port: 12345, port: 12345,
host: "smtptesthost.com", host: "smtptesthost.com",
from: "testfrom@test.com", from: "testfrom@test.com",
subject: "Hello!",
} }
}, null, controllers.config.save) }, null, controllers.config.save)
} }

View File

@ -1,7 +1,7 @@
module.exports = { module.exports = {
email: require("../../../controllers/admin/email"), email: require("../../../controllers/admin/email"),
groups: require("../../../controllers/admin/groups"), groups: require("../../../controllers/admin/groups"),
config: require("../../../controllers/admin/groups"), config: require("../../../controllers/admin/configs"),
templates: require("../../../controllers/admin/groups"), templates: require("../../../controllers/admin/templates"),
users: require("../../../controllers/admin/groups"), users: require("../../../controllers/admin/users"),
} }

View File

@ -30,7 +30,7 @@ const EmailTemplatePurpose = {
} }
const TemplateBindings = { const TemplateBindings = {
URL: "url", PLATFORM_URL: "platformUrl",
COMPANY: "company", COMPANY: "company",
LOGO_URL: "logoUrl", LOGO_URL: "logoUrl",
STYLES: "styles", STYLES: "styles",
@ -76,3 +76,4 @@ exports.TemplateTypes = TemplateTypes
exports.EmailTemplatePurpose = EmailTemplatePurpose exports.EmailTemplatePurpose = EmailTemplatePurpose
exports.TemplateMetadata = TemplateMetadata exports.TemplateMetadata = TemplateMetadata
exports.TemplateBindings = TemplateBindings exports.TemplateBindings = TemplateBindings
exports.GLOBAL_OWNER = "global"

View File

@ -47,7 +47,7 @@
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"> <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody><tr> <tbody><tr>
<td style="text-align: left; padding-left: 10px;"> <td style="text-align: left; padding-left: 10px;">
<h3 class="heading"><a href="{{ url }}">Budibase Platform</a></h3> <h3 class="heading"><a href="{{ platformUrl }}">Budibase Platform</a></h3>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
@ -64,7 +64,7 @@
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"> <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody><tr> <tbody><tr>
<td style="text-align: left; padding-right: 10px;"> <td style="text-align: left; padding-right: 10px;">
<p>© 2021 Restobar. All Rights Reserved</p> <p>© 2021 {{ company }}. All Rights Reserved</p>
</td> </td>
</tr> </tr>
</tbody></table> </tbody></table>
@ -79,4 +79,5 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</body> </body>
</html>

View File

@ -3,6 +3,7 @@ const {
EmailTemplatePurpose, EmailTemplatePurpose,
TemplateTypes, TemplateTypes,
TemplatePurpose, TemplatePurpose,
GLOBAL_OWNER,
} = require("../index") } = require("../index")
const { join } = require("path") const { join } = require("path")
const CouchDB = require("../../db") const CouchDB = require("../../db")
@ -10,14 +11,14 @@ const { getTemplateParams, StaticDatabases } = require("@budibase/auth").db
exports.EmailTemplates = { exports.EmailTemplates = {
[EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile( [EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile(
join(__dirname, "passwordRecovery.html") join(__dirname, "passwordRecovery.hbs")
), ),
[EmailTemplatePurpose.INVITATION]: readStaticFile( [EmailTemplatePurpose.INVITATION]: readStaticFile(
join(__dirname, "invitation.html") join(__dirname, "invitation.hbs")
), ),
[EmailTemplatePurpose.BASE]: readStaticFile(join(__dirname, "base.html")), [EmailTemplatePurpose.BASE]: readStaticFile(join(__dirname, "base.hbs")),
[EmailTemplatePurpose.STYLES]: readStaticFile( [EmailTemplatePurpose.STYLES]: readStaticFile(
join(__dirname, "style.css") join(__dirname, "style.hbs")
), ),
} }
@ -37,7 +38,11 @@ exports.addBaseTemplates = (templates, type = null) => {
continue continue
} }
if (exports.EmailTemplates[purpose]) { if (exports.EmailTemplates[purpose]) {
templates.push(exports.EmailTemplates[purpose]) templates.push({
contents: exports.EmailTemplates[purpose],
purpose,
type,
})
} }
} }
return templates return templates
@ -46,7 +51,7 @@ exports.addBaseTemplates = (templates, type = null) => {
exports.getTemplates = async ({ ownerId, type, id } = {}) => { exports.getTemplates = async ({ ownerId, type, id } = {}) => {
const db = new CouchDB(StaticDatabases.GLOBAL.name) const db = new CouchDB(StaticDatabases.GLOBAL.name)
const response = await db.allDocs( const response = await db.allDocs(
getTemplateParams(ownerId, id, { getTemplateParams(ownerId || GLOBAL_OWNER, id, {
include_docs: true, include_docs: true,
}) })
) )

View File

@ -15,17 +15,18 @@ exports.getSettingsTemplateContext = async () => {
}) })
) )
let settings = response.rows.map(row => row.doc)[0] || {} let settings = response.rows.map(row => row.doc)[0] || {}
if (!settings.url) { if (!settings.platformUrl) {
settings.url = LOCAL_URL settings.platformUrl = LOCAL_URL
} }
// TODO: need to fully spec out the context // TODO: need to fully spec out the context
const URL = settings.platformUrl
return { return {
[TemplateBindings.LOGO_URL]: settings.logoUrl || LOGO_URL, [TemplateBindings.LOGO_URL]: settings.logoUrl || LOGO_URL,
[TemplateBindings.URL]: settings.url, [TemplateBindings.PLATFORM_URL]: URL,
[TemplateBindings.REGISTRATION_URL]: checkSlashesInUrl( [TemplateBindings.REGISTRATION_URL]: checkSlashesInUrl(
`${settings.url}/registration` `${URL}/registration`
), ),
[TemplateBindings.RESET_URL]: checkSlashesInUrl(`${settings.url}/reset`), [TemplateBindings.RESET_URL]: checkSlashesInUrl(`${URL}/reset`),
[TemplateBindings.COMPANY]: settings.company || BASE_COMPANY, [TemplateBindings.COMPANY]: settings.company || BASE_COMPANY,
} }
} }