Finish global migration
This commit is contained in:
parent
8ae358d237
commit
63dd69f5b3
|
@ -71,6 +71,7 @@ jest.mock("../../../events", () => {
|
|||
},
|
||||
rows: {
|
||||
imported: jest.fn(),
|
||||
created: jest.fn(),
|
||||
},
|
||||
screen: {
|
||||
created: jest.fn(),
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import * as users from "./global/users"
|
||||
import * as rows from "./global/rows"
|
||||
import * as configs from "./global/configs"
|
||||
|
||||
/**
|
||||
* Date:
|
||||
* May 2022
|
||||
|
@ -6,4 +10,8 @@
|
|||
* Backfill global events.
|
||||
*/
|
||||
|
||||
export const run = async (db: any) => {}
|
||||
export const run = async (db: any) => {
|
||||
await users.backfill(db)
|
||||
await rows.backfill()
|
||||
await configs.backfill(db)
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
// EMAIL_SMTP_CREATED = "email:smtp:created",
|
||||
// AUTH_SSO_CREATED = "auth:sso:created",
|
||||
// AUTH_SSO_ACTIVATED = "auth:sso:activated",
|
||||
// AUTH_SSO_DEACTIVATED = "auth:sso:deactivated",
|
||||
// ORG_NAME_UPDATED = "org:info:name:updated",
|
||||
// ORG_LOGO_UPDATED = "org:info:logo:updated",
|
||||
// ORG_PLATFORM_URL_UPDATED = "org:platformurl:updated",
|
|
@ -0,0 +1,63 @@
|
|||
import { events, db } from "@budibase/backend-core"
|
||||
import {
|
||||
Config,
|
||||
isSMTPConfig,
|
||||
isGoogleConfig,
|
||||
isOIDCConfig,
|
||||
isSettingsConfig,
|
||||
} from "@budibase/types"
|
||||
import env from "./../../../../environment"
|
||||
|
||||
const getConfigs = async (globalDb: any): Promise<Config[]> => {
|
||||
const response = await globalDb.allDocs(
|
||||
db.getConfigParams(
|
||||
{},
|
||||
{
|
||||
include_docs: true,
|
||||
}
|
||||
)
|
||||
)
|
||||
return response.rows.map((row: any) => row.doc)
|
||||
}
|
||||
|
||||
export const backfill = async (globalDb: any) => {
|
||||
const configs = await getConfigs(globalDb)
|
||||
|
||||
for (const config of configs) {
|
||||
if (isSMTPConfig(config)) {
|
||||
events.email.SMTPCreated(config)
|
||||
}
|
||||
if (isGoogleConfig(config)) {
|
||||
events.auth.SSOCreated("google")
|
||||
if (config.config.activated) {
|
||||
events.auth.SSOActivated("google")
|
||||
}
|
||||
}
|
||||
if (isOIDCConfig(config)) {
|
||||
events.auth.SSOCreated("oidc")
|
||||
if (config.config.configs[0].activated) {
|
||||
events.auth.SSOActivated("oidc")
|
||||
}
|
||||
}
|
||||
if (isSettingsConfig(config)) {
|
||||
const company = config.config.company
|
||||
if (company && company !== "Budibase") {
|
||||
events.org.nameUpdated()
|
||||
}
|
||||
|
||||
const logoUrl = config.config.logoUrl
|
||||
if (logoUrl) {
|
||||
events.org.logoUpdated()
|
||||
}
|
||||
|
||||
const platformUrl = config.config.platformUrl
|
||||
if (
|
||||
platformUrl &&
|
||||
platformUrl !== "http://localhost:10000" &&
|
||||
env.SELF_HOSTED
|
||||
) {
|
||||
events.org.platformURLUpdated()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,5 +10,7 @@ export const backfill = async () => {
|
|||
const appIds = allApps ? allApps.map((app: { appId: any }) => app.appId) : []
|
||||
const rows: Row[] = await getUniqueRows(appIds)
|
||||
const rowCount = rows ? rows.length : 0
|
||||
events.rows.created(rowCount)
|
||||
if (rowCount) {
|
||||
events.rows.created(rowCount)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// USER_CREATED = "user:created",
|
||||
// USER_PERMISSION_ADMIN_ASSIGNED = "user:admin:assigned",
|
||||
// USER_PERMISSION_BUILDER_ASSIGNED = "user:builder:assigned",
|
|
@ -0,0 +1,38 @@
|
|||
import { events, db } from "@budibase/backend-core"
|
||||
import { User } from "@budibase/types"
|
||||
|
||||
// manually define user doc params - normally server doesn't read users from the db
|
||||
const getUserParams = (props: any) => {
|
||||
return db.getDocParams(db.DocumentTypes.USER, null, props)
|
||||
}
|
||||
|
||||
const getUsers = async (globalDb: any): Promise<User[]> => {
|
||||
const response = await globalDb.allDocs(
|
||||
getUserParams({
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
return response.rows.map((row: any) => row.doc)
|
||||
}
|
||||
|
||||
export const backfill = async (globalDb: any) => {
|
||||
const users = await getUsers(globalDb)
|
||||
|
||||
for (const user of users) {
|
||||
events.user.created(user)
|
||||
|
||||
if (user.admin?.global) {
|
||||
events.user.permissionAdminAssigned(user)
|
||||
}
|
||||
|
||||
if (user.builder?.global) {
|
||||
events.user.permissionBuilderAssigned(user)
|
||||
}
|
||||
|
||||
if (user.roles) {
|
||||
for (const [appId, role] of Object.entries(user.roles)) {
|
||||
events.role.assigned(user, role)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Mimic configs test configuration from worker, creation configs directly in database
|
||||
|
||||
import * as structures from "./structures"
|
||||
import { db } from "@budibase/backend-core"
|
||||
import { Config } from "@budibase/types"
|
||||
|
||||
export const saveSettingsConfig = async (globalDb: any) => {
|
||||
const config = structures.settings()
|
||||
await saveConfig(config, globalDb)
|
||||
}
|
||||
|
||||
export const saveGoogleConfig = async (globalDb: any) => {
|
||||
const config = structures.google()
|
||||
await saveConfig(config, globalDb)
|
||||
}
|
||||
|
||||
export const saveOIDCConfig = async (globalDb: any) => {
|
||||
const config = structures.oidc()
|
||||
await saveConfig(config, globalDb)
|
||||
}
|
||||
|
||||
export const saveSmtpConfig = async (globalDb: any) => {
|
||||
const config = structures.smtp()
|
||||
await saveConfig(config, globalDb)
|
||||
}
|
||||
|
||||
const saveConfig = async (config: Config, globalDb: any) => {
|
||||
config._id = db.generateConfigID({ type: config.type })
|
||||
await globalDb.put(config)
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import { events, migrations } from "@budibase/backend-core"
|
||||
import { events, migrations, tenancy } from "@budibase/backend-core"
|
||||
import TestConfig from "../../tests/utilities/TestConfiguration"
|
||||
import structures from "../../tests/utilities/structures"
|
||||
import { MIGRATIONS } from "../"
|
||||
import * as helpers from "./helpers"
|
||||
|
||||
jest.setTimeout(100000)
|
||||
|
||||
|
@ -57,4 +58,39 @@ describe("migrations", () => {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
it("runs global db migration", async () => {
|
||||
await config.doInContext(null, async () => {
|
||||
await config.createUser(undefined, undefined, false, true) // admin only
|
||||
await config.createUser(undefined, undefined, false, false) // non admin non builder
|
||||
await config.createTable()
|
||||
await config.createRow()
|
||||
await config.createRow()
|
||||
|
||||
const db = tenancy.getGlobalDB()
|
||||
await helpers.saveGoogleConfig(db)
|
||||
await helpers.saveOIDCConfig(db)
|
||||
await helpers.saveSettingsConfig(db)
|
||||
await helpers.saveSmtpConfig(db)
|
||||
|
||||
jest.clearAllMocks()
|
||||
const migration = MIGRATIONS.filter(
|
||||
m => m.name === "event_global_backfill"
|
||||
)[0]
|
||||
await migrations.runMigration(migration)
|
||||
|
||||
expect(events.user.created).toBeCalledTimes(3)
|
||||
expect(events.role.assigned).toBeCalledTimes(2)
|
||||
expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1) // default test user
|
||||
expect(events.user.permissionAdminAssigned).toBeCalledTimes(1) // admin from above
|
||||
expect(events.rows.created).toBeCalledTimes(1)
|
||||
expect(events.rows.created).toBeCalledWith(2)
|
||||
expect(events.email.SMTPCreated).toBeCalledTimes(1)
|
||||
expect(events.auth.SSOCreated).toBeCalledTimes(2)
|
||||
expect(events.auth.SSOActivated).toBeCalledTimes(2)
|
||||
expect(events.org.logoUpdated).toBeCalledTimes(1)
|
||||
expect(events.org.nameUpdated).toBeCalledTimes(1)
|
||||
expect(events.org.platformURLUpdated).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { utils } from "@budibase/backend-core"
|
||||
import {
|
||||
SMTPConfig,
|
||||
OIDCConfig,
|
||||
GoogleConfig,
|
||||
SettingsConfig,
|
||||
ConfigType,
|
||||
} from "@budibase/types"
|
||||
|
||||
export const oidc = (conf?: OIDCConfig): OIDCConfig => {
|
||||
return {
|
||||
type: ConfigType.OIDC,
|
||||
config: {
|
||||
configs: [
|
||||
{
|
||||
configUrl: "http://someconfigurl",
|
||||
clientID: "clientId",
|
||||
clientSecret: "clientSecret",
|
||||
logo: "Microsoft",
|
||||
name: "Active Directory",
|
||||
uuid: utils.newid(),
|
||||
activated: true,
|
||||
...conf,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const google = (conf?: GoogleConfig): GoogleConfig => {
|
||||
return {
|
||||
type: ConfigType.GOOGLE,
|
||||
config: {
|
||||
clientID: "clientId",
|
||||
clientSecret: "clientSecret",
|
||||
activated: true,
|
||||
...conf,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const smtp = (conf?: SMTPConfig): SMTPConfig => {
|
||||
return {
|
||||
type: ConfigType.SMTP,
|
||||
config: {
|
||||
port: 12345,
|
||||
host: "smtptesthost.com",
|
||||
from: "testfrom@test.com",
|
||||
subject: "Hello!",
|
||||
secure: false,
|
||||
...conf,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const settings = (conf?: SettingsConfig): SettingsConfig => {
|
||||
return {
|
||||
type: ConfigType.SETTINGS,
|
||||
config: {
|
||||
platformUrl: "http://mycustomdomain.com",
|
||||
logoUrl: "http://mylogourl,com",
|
||||
company: "mycompany",
|
||||
...conf,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -121,6 +121,7 @@ class TestConfiguration {
|
|||
async globalUser({
|
||||
id = GLOBAL_USER_ID,
|
||||
builder = true,
|
||||
admin = false,
|
||||
email = EMAIL,
|
||||
roles,
|
||||
} = {}) {
|
||||
|
@ -147,6 +148,11 @@ class TestConfiguration {
|
|||
} else {
|
||||
user.builder = { global: false }
|
||||
}
|
||||
if (admin) {
|
||||
user.admin = { global: true }
|
||||
} else {
|
||||
user.admin = { global: false }
|
||||
}
|
||||
const resp = await db.put(user)
|
||||
return {
|
||||
_rev: resp._rev,
|
||||
|
@ -155,9 +161,17 @@ class TestConfiguration {
|
|||
})
|
||||
}
|
||||
|
||||
async createUser(id = null, email = EMAIL) {
|
||||
async createUser(id = null, email = EMAIL, builder = true, admin = false) {
|
||||
const globalId = !id ? `us_${Math.random()}` : `us_${id}`
|
||||
const resp = await this.globalUser({ id: globalId, email })
|
||||
const appId = this.prodAppId
|
||||
const roles = { [appId]: "role_12345" }
|
||||
const resp = await this.globalUser({
|
||||
id: globalId,
|
||||
email,
|
||||
builder,
|
||||
admin,
|
||||
roles,
|
||||
})
|
||||
await userCache.invalidateUser(globalId)
|
||||
return {
|
||||
...resp,
|
||||
|
@ -277,7 +291,7 @@ class TestConfiguration {
|
|||
|
||||
// APP
|
||||
|
||||
async createApp(appName, opts = { deploy: true }) {
|
||||
async createApp(appName) {
|
||||
// create dev app
|
||||
// clear any old app
|
||||
this.appId = null
|
||||
|
@ -287,11 +301,9 @@ class TestConfiguration {
|
|||
await context.updateAppId(this.appId)
|
||||
|
||||
// create production app
|
||||
if (opts.deploy) {
|
||||
this.prodApp = await this.deploy()
|
||||
this.prodAppId = this.prodApp.appId
|
||||
this.allApps.push(this.prodApp)
|
||||
}
|
||||
this.prodApp = await this.deploy()
|
||||
this.prodAppId = this.prodApp.appId
|
||||
this.allApps.push(this.prodApp)
|
||||
|
||||
this.allApps.push(this.app)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface App extends Document {
|
||||
appId: string
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Automation extends Document {
|
||||
definition: {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Datasource extends Document {}
|
||||
|
|
|
@ -7,6 +7,6 @@ export * from "./role"
|
|||
export * from "./table"
|
||||
export * from "./screen"
|
||||
export * from "./view"
|
||||
export * from "./document"
|
||||
export * from "../document"
|
||||
export * from "./row"
|
||||
export * from "./user"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Layout extends Document {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Query extends Document {
|
||||
datasourceId: string
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Role extends Document {}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Row extends Document {}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Screen extends Document {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
import { View } from "./view"
|
||||
|
||||
export interface Table extends Document {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Document } from "./document"
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface UserMetadata extends Document {
|
||||
roleId: string
|
||||
|
|
|
@ -1 +1,67 @@
|
|||
export interface SMTPConfig {}
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface Config extends Document {
|
||||
type: ConfigType
|
||||
}
|
||||
|
||||
export interface SMTPConfig extends Config {
|
||||
config: {
|
||||
port: number
|
||||
host: string
|
||||
from: string
|
||||
subject: string
|
||||
secure: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface SettingsConfig extends Config {
|
||||
config: {
|
||||
company: string
|
||||
logoUrl: string
|
||||
platformUrl: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface GoogleConfig extends Config {
|
||||
config: {
|
||||
clientID: string
|
||||
clientSecret: string
|
||||
activated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface OIDCConfig extends Config {
|
||||
config: {
|
||||
configs: {
|
||||
configUrl: string
|
||||
clientID: string
|
||||
clientSecret: string
|
||||
logo: string
|
||||
name: string
|
||||
uuid: string
|
||||
activated: boolean
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
export type NestedConfig =
|
||||
| SMTPConfig
|
||||
| SettingsConfig
|
||||
| GoogleConfig
|
||||
| OIDCConfig
|
||||
|
||||
export const isSettingsConfig = (config: Config): config is SettingsConfig =>
|
||||
config.type === ConfigType.SETTINGS
|
||||
export const isSMTPConfig = (config: Config): config is SMTPConfig =>
|
||||
config.type === ConfigType.SMTP
|
||||
export const isGoogleConfig = (config: Config): config is GoogleConfig =>
|
||||
config.type === ConfigType.GOOGLE
|
||||
export const isOIDCConfig = (config: Config): config is OIDCConfig =>
|
||||
config.type === ConfigType.OIDC
|
||||
|
||||
export enum ConfigType {
|
||||
SETTINGS = "settings",
|
||||
SMTP = "smtp",
|
||||
GOOGLE = "google",
|
||||
OIDC = "oidc",
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
export interface User {
|
||||
import { Document } from "../document"
|
||||
|
||||
export interface User extends Document {
|
||||
roles: UserRoles
|
||||
builder?: {
|
||||
global: boolean
|
||||
}
|
||||
admin?: {
|
||||
global: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export interface UserRoles {
|
||||
|
|
Loading…
Reference in New Issue