1
0
Fork 0
mirror of synced 2024-06-14 08:24:48 +12:00

sso auth + datasource events, test updates

This commit is contained in:
Rory Powell 2022-04-05 15:46:04 +01:00
parent 7a5df9010c
commit 39ef2438a3
29 changed files with 171 additions and 52 deletions

View file

@ -1,5 +1,17 @@
const PosthogClient = require("./posthog")
const env = require("../environment")
const { getTenantId } = require("../context")
const IdentityType = {
TENANT: "tenant",
USER: "user",
ACCOUNT: "account",
}
const Hosting = {
CLOUD: "cloud",
SELF: "self",
}
class Analytics {
constructor() {
@ -14,9 +26,38 @@ class Analytics {
return this.isEnabled
}
updateUser(userId, properties) {
identify(type, id, hosting) {
if (!this.isEnabled) return
this.posthog.updateUser(userId, properties)
const tenantId = getTenantId()
if (!hosting) {
hosting = env.SELF_HOSTED ? Hosting.SELF : Hosting.CLOUD
}
const properties = {
type,
hosting,
tenant: tenantId,
}
this.posthog.identify(id, properties)
}
identifyUser(userId) {
this.identify(IdentityType.USER, userId)
}
identifyTenant() {
let distinctId
if (env.SELF_HOSTED) {
distinctId = getTenantId() // TODO: Get installation ID
} else {
distinctId = getTenantId()
}
this.identify(IdentityType.TENANT, distinctId)
}
identifyAccount(account) {
const distinctId = account.accountId
const hosting = account.hosting
this.identify(IdentityType.ACCOUNT, distinctId, hosting)
}
captureEvent(eventName, properties) {

View file

@ -5,8 +5,8 @@ class PosthogClient {
this.posthog = new PostHog(token)
}
updateUser(userId, properties) {
this.posthog.identify({ distinctId: userId, properties })
identify(distinctId, properties) {
this.posthog.identify({ distinctId, properties })
}
capture(userId, event, properties) {

View file

@ -1,8 +1,8 @@
const { MOCK_DATE } = require("../../tests/utilities/TestConfiguration")
require("../../tests/utilities/TestConfiguration")
const { mocks } = require("../../tests/utilities")
mocks.date.mock()
const { getDB, allDbs } = require("../")
Date = jest.fn(() => MOCK_DATE)
describe("db", () => {
describe("getDB", () => {
@ -19,8 +19,8 @@ describe("db", () => {
let doc = { _id: "test" }
await db.put(doc)
doc = await db.get(doc._id)
expect(doc.createdAt).toBe(MOCK_DATE.toISOString())
expect(doc.updatedAt).toBe(MOCK_DATE.toISOString())
expect(doc.createdAt).toBe(new Date().toISOString())
expect(doc.updatedAt).toBe(new Date().toISOString())
await db.destroy()
})
})

View file

@ -131,4 +131,9 @@ exports.Events = {
// LICENSING
LICENSING_QUOTA_EXCEEDED: "licensing:quota:exceeded",
// ACCOUNT
ACCOUNT_CREATED: "account:created",
ACCOUNT_DELETED: "account:deleted",
ACCOUNT_VERIFIED: "account:verified",
}

View file

@ -0,0 +1,17 @@
const events = require("../events")
const { Events } = require("../constants")
exports.created = () => {
const properties = {}
events.processEvent(Events.ACCOUNT_CREATED, properties)
}
exports.deleted = () => {
const properties = {}
events.processEvent(Events.ACCOUNT_DELETED, properties)
}
exports.verified = () => {
const properties = {}
events.processEvent(Events.ACCOUNT_VERIFIED, properties)
}

View file

@ -53,7 +53,6 @@ exports.reverted = () => {
events.processEvent(Events.APP_REVERTED, properties)
}
// TODO
exports.exported = () => {
const properties = {}
events.processEvent(Events.APP_EXPORTED, properties)

View file

@ -1,16 +1,20 @@
const events = require("../events")
const { Events } = require("../constants")
exports.login = () => {
const properties = {}
exports.login = source => {
const properties = {
source,
}
events.processEvent(Events.AUTH_LOGIN, properties)
}
// TODO
exports.logout = () => {
const properties = {}
events.processEvent(Events.AUTH_LOGOUT, properties)
}
// TODO
exports.SSOCreated = type => {
const properties = {
type,
@ -18,6 +22,7 @@ exports.SSOCreated = type => {
events.processEvent(Events.AUTH_SSO_CREATED, properties)
}
// TODO
exports.SSOUpdated = type => {
const properties = {
type,
@ -25,6 +30,7 @@ exports.SSOUpdated = type => {
events.processEvent(Events.AUTH_SSO_UPDATED, properties)
}
// TODO
exports.SSOActivated = type => {
const properties = {
type,
@ -32,6 +38,7 @@ exports.SSOActivated = type => {
events.processEvent(Events.AUTH_SSO_ACTIVATED, properties)
}
// TODO
exports.SSODeactivated = type => {
const properties = {
type,

View file

@ -6,13 +6,11 @@ exports.created = () => {
events.processEvent(Events.DATASOURCE_CREATED, properties)
}
// TODO
exports.updated = () => {
const properties = {}
events.processEvent(Events.DATASOURCE_UPDATED, properties)
}
// TODO
exports.deleted = () => {
const properties = {}
events.processEvent(Events.DATASOURCE_DELETED, properties)

View file

@ -22,4 +22,5 @@ module.exports = {
featureFlags: require("./featureFlags"),
events: require("./events"),
analytics: require("./analytics"),
testUtils: require("./tests/utilities"),
}

View file

@ -1,12 +1,12 @@
const { MOCK_DATE_TIMESTAMP, MOCK_DATE } = require("../../tests/utilities/TestConfiguration")
require("../../tests/utilities/TestConfiguration")
const { mocks } = require("../../tests/utilities")
mocks.date.mock()
const { runMigrations, getMigrationsDoc } = require("../index")
const { getDB } = require("../../db")
const {
StaticDatabases,
} = require("../../db/utils")
Date = jest.fn(() => MOCK_DATE)
Date.now = jest.fn(() => MOCK_DATE_TIMESTAMP)
let db
describe("migrations", () => {

View file

@ -1,4 +1 @@
require("./db")
exports.MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
exports.MOCK_DATE_TIMESTAMP = 1577836800000

View file

@ -0,0 +1,5 @@
const mocks = require("./mocks")
module.exports = {
mocks,
}

View file

@ -0,0 +1,13 @@
exports.MOCK_DATE = new Date("2020-01-01T00:00:00.000Z")
exports.MOCK_DATE_TIMESTAMP = 1577836800000
exports.mock = () => {
// eslint-disable-next-line no-global-assign
Date = jest.fn(() => exports.MOCK_DATE)
Date.now = jest.fn(() => exports.MOCK_DATE_TIMESTAMP)
return {
MOCK_DATE: exports.MOCK_DATE,
MOCK_DATE_TIMESTAMP: exports.MOCK_DATE_TIMESTAMP,
}
}

View file

@ -1,5 +1,3 @@
const core = require("@budibase/backend-core")
const events = {
app: {
created: jest.fn(),
@ -14,9 +12,14 @@ const events = {
reverted: jest.fn(),
exported: jest.fn(),
},
auth: {
login: jest.fn(),
},
datasource: {
created: jest.fn(),
updated: jest.fn(),
deleted: jest.fn(),
},
}
core.events = events
module.exports = {
events,
}
module.exports = events

View file

@ -0,0 +1,7 @@
const events = require("./events")
const date = require("./date")
module.exports = {
events,
date,
}

View file

@ -109,6 +109,7 @@ exports.update = async function (ctx) {
}
const response = await db.put(datasource)
events.datasource.updated()
datasource._rev = response.rev
// Drain connection pools when configuration is changed
@ -143,7 +144,7 @@ exports.save = async function (ctx) {
}
const dbResp = await db.put(datasource)
events.datasourceCreated(datasource)
events.datasource.created()
datasource._rev = dbResp.rev
// Drain connection pools when configuration is changed
@ -178,6 +179,7 @@ exports.destroy = async function (ctx) {
// delete the datasource
await db.remove(ctx.params.datasourceId, ctx.params.revId)
events.datasource.deleted()
ctx.message = `Datasource deleted.`
ctx.status = 200

View file

@ -7,7 +7,8 @@ Array [
"entities": Array [
Object {
"_id": "ta_users",
"_rev": "1-039883a06c1f9cb3945731d79838181e",
"_rev": "1-6f4013e796887f1771bf7837598d87e7",
"createdAt": "2020-01-01T00:00:00.000Z",
"name": "Users",
"primaryDisplay": "email",
"schema": Object {
@ -72,6 +73,7 @@ Array [
},
},
"type": "table",
"updatedAt": "2020-01-01T00:00:00.000Z",
"views": Object {},
},
],
@ -81,9 +83,11 @@ Array [
},
Object {
"config": Object {},
"createdAt": "2020-01-01T00:00:00.000Z",
"name": "Test",
"source": "POSTGRES",
"type": "datasource",
"updatedAt": "2020-01-01T00:00:00.000Z",
},
]
`;

View file

@ -18,6 +18,7 @@ const {
} = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { AppStatus } = require("../../../db/utils")
const { events } = require("@budibase/backend-core")
describe("/applications", () => {
let request = setup.getRequest()
@ -40,7 +41,7 @@ describe("/applications", () => {
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
expect(config.getEvents().app.created.mock.calls.length).toBe(1)
expect(events.app.created.mock.calls.length).toBe(1)
})
it("creates app from template", async () => {
@ -54,8 +55,8 @@ describe("/applications", () => {
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
expect(config.getEvents().app.created.mock.calls.length).toBe(1)
expect(config.getEvents().app.templateImported.mock.calls.length).toBe(1)
expect(events.app.created.mock.calls.length).toBe(1)
expect(events.app.templateImported.mock.calls.length).toBe(1)
})
@ -69,8 +70,8 @@ describe("/applications", () => {
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._id).toBeDefined()
expect(config.getEvents().app.created.mock.calls.length).toBe(1)
expect(config.getEvents().app.fileImported.mock.calls.length).toBe(1)
expect(events.app.created.mock.calls.length).toBe(1)
expect(events.app.fileImported.mock.calls.length).toBe(1)
})
it("should apply authorization to endpoint", async () => {
@ -134,7 +135,7 @@ describe("/applications", () => {
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.rev).toBeDefined()
expect(config.getEvents().app.updated.mock.calls.length).toBe(1)
expect(events.app.updated.mock.calls.length).toBe(1)
})
})
@ -147,7 +148,7 @@ describe("/applications", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.deleted.mock.calls.length).toBe(1)
expect(events.app.deleted.mock.calls.length).toBe(1)
})
it("should unpublish app", async () => {
@ -158,7 +159,7 @@ describe("/applications", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.unpublished.mock.calls.length).toBe(1)
expect(events.app.unpublished.mock.calls.length).toBe(1)
})
})
@ -170,7 +171,7 @@ describe("/applications", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.versionUpdated.mock.calls.length).toBe(1)
expect(events.app.versionUpdated.mock.calls.length).toBe(1)
})
it("should be able to revert the app client library version", async () => {
// We need to first update the version so that we can then revert
@ -184,7 +185,7 @@ describe("/applications", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.versionReverted.mock.calls.length).toBe(1)
expect(events.app.versionReverted.mock.calls.length).toBe(1)
})
})

View file

@ -6,7 +6,8 @@ const {
} = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { basicAutomation } = setup.structures
const { testUtils } = require("@budibase/backend-core")
testUtils.mocks.date.mock()
const MAX_RETRIES = 4
let ACTION_DEFINITIONS = {}

View file

@ -2,6 +2,7 @@ jest.mock("../../../utilities/fileSystem/utilities")
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { events } = require("@budibase/backend-core")
describe("/backups", () => {
let request = setup.getRequest()
@ -21,7 +22,7 @@ describe("/backups", () => {
.expect(200)
expect(res.text).toBeDefined()
expect(res.text.includes(`"db_name":"${config.getAppId()}"`)).toEqual(true)
expect(config.getEvents().app.exported.mock.calls.length).toBe(1)
expect(events.app.exported.mock.calls.length).toBe(1)
})
it("should apply authorization to endpoint", async () => {

View file

@ -5,6 +5,8 @@ let { basicDatasource } = setup.structures
let { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const pg = require("pg")
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
const { events, testUtils } = require("@budibase/backend-core")
testUtils.mocks.date.mock()
describe("/datasources", () => {
let request = setup.getRequest()
@ -16,6 +18,7 @@ describe("/datasources", () => {
beforeEach(async () => {
await config.init()
datasource = await config.createDatasource()
jest.clearAllMocks()
})
describe("create", () => {
@ -29,6 +32,7 @@ describe("/datasources", () => {
expect(res.body.datasource.name).toEqual("Test")
expect(res.body.errors).toBeUndefined()
expect(events.datasource.created.mock.calls.length).toBe(1)
})
})
@ -44,6 +48,7 @@ describe("/datasources", () => {
expect(res.body.datasource.name).toEqual("Updated Test")
expect(res.body.errors).toBeUndefined()
expect(events.datasource.updated.mock.calls.length).toBe(1)
})
describe("dynamic variables", () => {
@ -160,6 +165,7 @@ describe("/datasources", () => {
.expect(200)
expect(res.body.length).toEqual(1)
expect(events.datasource.deleted.mock.calls.length).toBe(1)
})
it("should apply authorization to endpoint", async () => {

View file

@ -1,4 +1,5 @@
const setup = require("./utilities")
const { events } = require("@budibase/backend-core")
describe("/deployments", () => {
let request = setup.getRequest()
@ -18,7 +19,7 @@ describe("/deployments", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.published.mock.calls.length).toBe(1)
expect(events.app.published.mock.calls.length).toBe(1)
})
})
})

View file

@ -1,4 +1,5 @@
const setup = require("./utilities")
const { events } = require("@budibase/backend-core")
describe("/dev", () => {
let request = setup.getRequest()
@ -18,7 +19,7 @@ describe("/dev", () => {
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(config.getEvents().app.reverted.mock.calls.length).toBe(1)
expect(events.app.reverted.mock.calls.length).toBe(1)
})
})
})

View file

@ -13,6 +13,8 @@ const setup = require("./utilities")
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
const { basicQuery, basicDatasource } = setup.structures
const { testUtils } = require("@budibase/backend-core")
testUtils.mocks.date.mock()
describe("/queries", () => {
let request = setup.getRequest()
@ -56,6 +58,8 @@ describe("/queries", () => {
_rev: res.body._rev,
_id: res.body._id,
...query,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
})
})
})
@ -73,7 +77,9 @@ describe("/queries", () => {
{
_rev: query._rev,
_id: query._id,
createdAt: new Date().toISOString(),
...basicQuery(datasource._id),
updatedAt: new Date().toISOString(),
readable: true,
},
])

View file

@ -2,9 +2,7 @@ const { outputProcessing } = require("../../../utilities/rowProcessor")
const setup = require("./utilities")
const { basicRow } = setup.structures
const { doInAppContext } = require("@budibase/backend-core/context")
// mock the fetch for the search system
jest.mock("node-fetch")
const { testUtils } = require("@budibase/backend-core")
describe("/rows", () => {
let request = setup.getRequest()
@ -69,6 +67,10 @@ describe("/rows", () => {
.expect('Content-Type', /json/)
.expect(200)
// can't mock dates due to coercion test requiring real Date clas
delete res.body.createdAt
delete res.body.updatedAt
expect(res.body).toEqual({
...row,
_id: existing._id,

View file

@ -1,3 +1,4 @@
require("./mocks")
require("../../db").init()
const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles")
const env = require("../../environment")
@ -25,7 +26,6 @@ const newid = require("../../db/newid")
const context = require("@budibase/backend-core/context")
const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db")
const { encrypt } = require("@budibase/backend-core/encryption")
const { events } = require("./mockEvents")
const GLOBAL_USER_ID = "us_uuid1"
const EMAIL = "babs@babs.com"
@ -60,10 +60,6 @@ class TestConfiguration {
return this.prodAppId
}
getEvents() {
return events
}
async _req(config, params, controlFunc) {
const request = {}
// fake cookies, we don't need them

View file

@ -0,0 +1,2 @@
const core = require("@budibase/backend-core")
core.events = core.testUtils.mocks.events

View file

@ -0,0 +1 @@
require("./events")

View file

@ -22,6 +22,7 @@ const {
} = require("@budibase/backend-core/tenancy")
const env = require("../../../environment")
import { users } from "@budibase/pro"
const { events } = require("@budibase/backend-core")
const ssoCallbackUrl = async (config: any, type: any) => {
// incase there is a callback URL from before
@ -77,6 +78,7 @@ export const authenticate = async (ctx: any, next: any) => {
"local",
async (err: any, user: any, info: any) => {
await authInternal(ctx, user, err, info)
events.auth.login("local")
ctx.status = 200
}
)(ctx, next)
@ -213,7 +215,7 @@ export const googleAuth = async (ctx: any, next: any) => {
{ successRedirect: "/", failureRedirect: "/error" },
async (err: any, user: any, info: any) => {
await authInternal(ctx, user, err, info)
events.auth.login("google")
ctx.redirect("/")
}
)(ctx, next)
@ -257,7 +259,7 @@ export const oidcAuth = async (ctx: any, next: any) => {
{ successRedirect: "/", failureRedirect: "/error" },
async (err: any, user: any, info: any) => {
await authInternal(ctx, user, err, info)
events.auth.login("oidc")
ctx.redirect("/")
}
)(ctx, next)