More controller typescript conversions.
This commit is contained in:
parent
8a4da7d4ce
commit
92210144ff
16 changed files with 284 additions and 261 deletions
|
@ -171,7 +171,7 @@ export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
|
||||||
/**
|
/**
|
||||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||||
*/
|
*/
|
||||||
export function getUserMetadataParams(userId?: string, otherProps = {}) {
|
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
|
||||||
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
|
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ export function getTemplateParams(
|
||||||
* Generates a new role ID.
|
* Generates a new role ID.
|
||||||
* @returns {string} The new role ID which the role doc can be stored under.
|
* @returns {string} The new role ID which the role doc can be stored under.
|
||||||
*/
|
*/
|
||||||
export function generateRoleID(id: any) {
|
export function generateRoleID(id?: any) {
|
||||||
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
|
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ const EXTERNAL_BUILTIN_ROLE_IDS = [
|
||||||
|
|
||||||
export class Role implements RoleDoc {
|
export class Role implements RoleDoc {
|
||||||
_id: string
|
_id: string
|
||||||
|
_rev?: string
|
||||||
name: string
|
name: string
|
||||||
permissionId: string
|
permissionId: string
|
||||||
inherits?: string
|
inherits?: string
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
const { StaticDatabases } = require("@budibase/backend-core/db")
|
import { db as dbCore, tenancy } from "@budibase/backend-core"
|
||||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
import { BBContext, Document } from "@budibase/types"
|
||||||
|
|
||||||
const KEYS_DOC = StaticDatabases.GLOBAL.docs.apiKeys
|
const KEYS_DOC = dbCore.StaticDatabases.GLOBAL.docs.apiKeys
|
||||||
|
|
||||||
async function getBuilderMainDoc() {
|
async function getBuilderMainDoc() {
|
||||||
const db = getGlobalDB()
|
const db = tenancy.getGlobalDB()
|
||||||
try {
|
try {
|
||||||
return await db.get(KEYS_DOC)
|
return await db.get(KEYS_DOC)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -15,24 +15,24 @@ async function getBuilderMainDoc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setBuilderMainDoc(doc) {
|
async function setBuilderMainDoc(doc: Document) {
|
||||||
// make sure to override the ID
|
// make sure to override the ID
|
||||||
doc._id = KEYS_DOC
|
doc._id = KEYS_DOC
|
||||||
const db = getGlobalDB()
|
const db = tenancy.getGlobalDB()
|
||||||
return db.put(doc)
|
return db.put(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
export async function fetch(ctx: BBContext) {
|
||||||
try {
|
try {
|
||||||
const mainDoc = await getBuilderMainDoc()
|
const mainDoc = await getBuilderMainDoc()
|
||||||
ctx.body = mainDoc.apiKeys ? mainDoc.apiKeys : {}
|
ctx.body = mainDoc.apiKeys ? mainDoc.apiKeys : {}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
ctx.throw(400, err)
|
ctx.throw(400, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.update = async function (ctx) {
|
export async function update(ctx: BBContext) {
|
||||||
const key = ctx.params.key
|
const key = ctx.params.key
|
||||||
const value = ctx.request.body.value
|
const value = ctx.request.body.value
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ exports.update = async function (ctx) {
|
||||||
_id: resp.id,
|
_id: resp.id,
|
||||||
_rev: resp.rev,
|
_rev: resp.rev,
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
ctx.throw(400, err)
|
ctx.throw(400, err)
|
||||||
}
|
}
|
|
@ -1,26 +1,21 @@
|
||||||
const actions = require("../../automations/actions")
|
import actions from "../../automations/actions"
|
||||||
const triggers = require("../../automations/triggers")
|
import triggers from "../../automations/triggers"
|
||||||
const {
|
import {
|
||||||
getAutomationParams,
|
getAutomationParams,
|
||||||
generateAutomationID,
|
generateAutomationID,
|
||||||
DocumentType,
|
DocumentType,
|
||||||
} = require("../../db/utils")
|
} from "../../db/utils"
|
||||||
const {
|
import {
|
||||||
checkForWebhooks,
|
checkForWebhooks,
|
||||||
updateTestHistory,
|
updateTestHistory,
|
||||||
removeDeprecated,
|
removeDeprecated,
|
||||||
} = require("../../automations/utils")
|
} from "../../automations/utils"
|
||||||
const { deleteEntityMetadata } = require("../../utilities")
|
import { deleteEntityMetadata } from "../../utilities"
|
||||||
const { MetadataTypes } = require("../../constants")
|
import { MetadataTypes } from "../../constants"
|
||||||
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
import { setTestFlag, clearTestFlag } from "../../utilities/redis"
|
||||||
const {
|
import { context, cache, events } from "@budibase/backend-core"
|
||||||
getAppDB,
|
import { automations } from "@budibase/pro"
|
||||||
getProdAppDB,
|
import { Automation, BBContext } from "@budibase/types"
|
||||||
doInAppContext,
|
|
||||||
} = require("@budibase/backend-core/context")
|
|
||||||
const { events } = require("@budibase/backend-core")
|
|
||||||
const { app } = require("@budibase/backend-core/cache")
|
|
||||||
const { automations } = require("@budibase/pro")
|
|
||||||
|
|
||||||
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
|
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
|
||||||
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
||||||
|
@ -31,7 +26,7 @@ const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
||||||
* *
|
* *
|
||||||
*************************/
|
*************************/
|
||||||
|
|
||||||
async function cleanupAutomationMetadata(automationId) {
|
async function cleanupAutomationMetadata(automationId: string) {
|
||||||
await deleteEntityMetadata(MetadataTypes.AUTOMATION_TEST_INPUT, automationId)
|
await deleteEntityMetadata(MetadataTypes.AUTOMATION_TEST_INPUT, automationId)
|
||||||
await deleteEntityMetadata(
|
await deleteEntityMetadata(
|
||||||
MetadataTypes.AUTOMATION_TEST_HISTORY,
|
MetadataTypes.AUTOMATION_TEST_HISTORY,
|
||||||
|
@ -39,7 +34,7 @@ async function cleanupAutomationMetadata(automationId) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanAutomationInputs(automation) {
|
function cleanAutomationInputs(automation: Automation) {
|
||||||
if (automation == null) {
|
if (automation == null) {
|
||||||
return automation
|
return automation
|
||||||
}
|
}
|
||||||
|
@ -63,14 +58,14 @@ function cleanAutomationInputs(automation) {
|
||||||
return automation
|
return automation
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.create = async function (ctx) {
|
export async function create(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let automation = ctx.request.body
|
let automation = ctx.request.body
|
||||||
automation.appId = ctx.appId
|
automation.appId = ctx.appId
|
||||||
|
|
||||||
// call through to update if already exists
|
// call through to update if already exists
|
||||||
if (automation._id && automation._rev) {
|
if (automation._id && automation._rev) {
|
||||||
return exports.update(ctx)
|
return update(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
automation._id = generateAutomationID()
|
automation._id = generateAutomationID()
|
||||||
|
@ -97,17 +92,23 @@ exports.create = async function (ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getNewSteps = (oldAutomation, automation) => {
|
export function getNewSteps(oldAutomation: Automation, automation: Automation) {
|
||||||
const oldStepIds = oldAutomation.definition.steps.map(s => s.id)
|
const oldStepIds = oldAutomation.definition.steps.map(s => s.id)
|
||||||
return automation.definition.steps.filter(s => !oldStepIds.includes(s.id))
|
return automation.definition.steps.filter(s => !oldStepIds.includes(s.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDeletedSteps = (oldAutomation, automation) => {
|
export function getDeletedSteps(
|
||||||
|
oldAutomation: Automation,
|
||||||
|
automation: Automation
|
||||||
|
) {
|
||||||
const stepIds = automation.definition.steps.map(s => s.id)
|
const stepIds = automation.definition.steps.map(s => s.id)
|
||||||
return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id))
|
return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleStepEvents = async (oldAutomation, automation) => {
|
export async function handleStepEvents(
|
||||||
|
oldAutomation: Automation,
|
||||||
|
automation: Automation
|
||||||
|
) {
|
||||||
// new steps
|
// new steps
|
||||||
const newSteps = getNewSteps(oldAutomation, automation)
|
const newSteps = getNewSteps(oldAutomation, automation)
|
||||||
for (let step of newSteps) {
|
for (let step of newSteps) {
|
||||||
|
@ -121,8 +122,8 @@ const handleStepEvents = async (oldAutomation, automation) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.update = async function (ctx) {
|
export async function update(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let automation = ctx.request.body
|
let automation = ctx.request.body
|
||||||
automation.appId = ctx.appId
|
automation.appId = ctx.appId
|
||||||
const oldAutomation = await db.get(automation._id)
|
const oldAutomation = await db.get(automation._id)
|
||||||
|
@ -146,9 +147,8 @@ exports.update = async function (ctx) {
|
||||||
if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) {
|
if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) {
|
||||||
await events.automation.triggerUpdated(automation)
|
await events.automation.triggerUpdated(automation)
|
||||||
await deleteEntityMetadata(
|
await deleteEntityMetadata(
|
||||||
ctx.appId,
|
|
||||||
MetadataTypes.AUTOMATION_TEST_INPUT,
|
MetadataTypes.AUTOMATION_TEST_INPUT,
|
||||||
automation._id
|
automation._id!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +165,8 @@ exports.update = async function (ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
export async function fetch(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getAutomationParams(null, {
|
getAutomationParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -175,13 +175,13 @@ exports.fetch = async function (ctx) {
|
||||||
ctx.body = response.rows.map(row => row.doc)
|
ctx.body = response.rows.map(row => row.doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async function (ctx) {
|
export async function find(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
ctx.body = await db.get(ctx.params.id)
|
ctx.body = await db.get(ctx.params.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async function (ctx) {
|
export async function destroy(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const automationId = ctx.params.id
|
const automationId = ctx.params.id
|
||||||
const oldAutomation = await db.get(automationId)
|
const oldAutomation = await db.get(automationId)
|
||||||
await checkForWebhooks({
|
await checkForWebhooks({
|
||||||
|
@ -193,14 +193,14 @@ exports.destroy = async function (ctx) {
|
||||||
await events.automation.deleted(oldAutomation)
|
await events.automation.deleted(oldAutomation)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.logSearch = async function (ctx) {
|
export async function logSearch(ctx: BBContext) {
|
||||||
ctx.body = await automations.logs.logSearch(ctx.request.body)
|
ctx.body = await automations.logs.logSearch(ctx.request.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.clearLogError = async function (ctx) {
|
export async function clearLogError(ctx: BBContext) {
|
||||||
const { automationId, appId } = ctx.request.body
|
const { automationId, appId } = ctx.request.body
|
||||||
await doInAppContext(appId, async () => {
|
await context.doInAppContext(appId, async () => {
|
||||||
const db = getProdAppDB()
|
const db = context.getProdAppDB()
|
||||||
const metadata = await db.get(DocumentType.APP_METADATA)
|
const metadata = await db.get(DocumentType.APP_METADATA)
|
||||||
if (!automationId) {
|
if (!automationId) {
|
||||||
delete metadata.automationErrors
|
delete metadata.automationErrors
|
||||||
|
@ -211,20 +211,20 @@ exports.clearLogError = async function (ctx) {
|
||||||
delete metadata.automationErrors[automationId]
|
delete metadata.automationErrors[automationId]
|
||||||
}
|
}
|
||||||
await db.put(metadata)
|
await db.put(metadata)
|
||||||
await app.invalidateAppMetadata(metadata.appId, metadata)
|
await cache.app.invalidateAppMetadata(metadata.appId, metadata)
|
||||||
ctx.body = { message: `Error logs cleared.` }
|
ctx.body = { message: `Error logs cleared.` }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getActionList = async function (ctx) {
|
export async function getActionList(ctx: BBContext) {
|
||||||
ctx.body = ACTION_DEFS
|
ctx.body = ACTION_DEFS
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getTriggerList = async function (ctx) {
|
export async function getTriggerList(ctx: BBContext) {
|
||||||
ctx.body = TRIGGER_DEFS
|
ctx.body = TRIGGER_DEFS
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.getDefinitionList = async function (ctx) {
|
export async function getDefinitionList(ctx: BBContext) {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
trigger: TRIGGER_DEFS,
|
trigger: TRIGGER_DEFS,
|
||||||
action: ACTION_DEFS,
|
action: ACTION_DEFS,
|
||||||
|
@ -237,8 +237,8 @@ module.exports.getDefinitionList = async function (ctx) {
|
||||||
* *
|
* *
|
||||||
*********************/
|
*********************/
|
||||||
|
|
||||||
exports.trigger = async function (ctx) {
|
export async function trigger(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let automation = await db.get(ctx.params.id)
|
let automation = await db.get(ctx.params.id)
|
||||||
await triggers.externalTrigger(automation, {
|
await triggers.externalTrigger(automation, {
|
||||||
...ctx.request.body,
|
...ctx.request.body,
|
||||||
|
@ -250,7 +250,7 @@ exports.trigger = async function (ctx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareTestInput(input) {
|
function prepareTestInput(input: any) {
|
||||||
// prepare the test parameters
|
// prepare the test parameters
|
||||||
if (input.id && input.row) {
|
if (input.id && input.row) {
|
||||||
input.row._id = input.id
|
input.row._id = input.id
|
||||||
|
@ -261,8 +261,8 @@ function prepareTestInput(input) {
|
||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.test = async function (ctx) {
|
export async function test(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let automation = await db.get(ctx.params.id)
|
let automation = await db.get(ctx.params.id)
|
||||||
await setTestFlag(automation._id)
|
await setTestFlag(automation._id)
|
||||||
const testInput = prepareTestInput(ctx.request.body)
|
const testInput = prepareTestInput(ctx.request.body)
|
|
@ -1,14 +1,15 @@
|
||||||
const env = require("../../environment")
|
import env from "../../environment"
|
||||||
const { getAllApps, getGlobalDBName } = require("@budibase/backend-core/db")
|
import { db as dbCore, tenancy } from "@budibase/backend-core"
|
||||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
import { streamFile } from "../../utilities/fileSystem"
|
||||||
const { streamFile } = require("../../utilities/fileSystem")
|
import { stringToReadStream } from "../../utilities"
|
||||||
const { stringToReadStream } = require("../../utilities")
|
import { getDocParams, DocumentType, isDevAppID } from "../../db/utils"
|
||||||
const { getDocParams, DocumentType, isDevAppID } = require("../../db/utils")
|
import { create } from "./application"
|
||||||
const { create } = require("./application")
|
import { join } from "path"
|
||||||
const { join } = require("path")
|
import { App, BBContext, Database } from "@budibase/types"
|
||||||
const sdk = require("../../sdk")
|
import sdk from "../../sdk"
|
||||||
|
import { getAllApps } from "@budibase/backend-core/src/db"
|
||||||
|
|
||||||
async function createApp(appName, appDirectory) {
|
async function createApp(appName: string, appDirectory: string) {
|
||||||
const ctx = {
|
const ctx = {
|
||||||
request: {
|
request: {
|
||||||
body: {
|
body: {
|
||||||
|
@ -25,7 +26,7 @@ async function createApp(appName, appDirectory) {
|
||||||
return create(ctx)
|
return create(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAllDocType(db, docType) {
|
async function getAllDocType(db: Database, docType: string) {
|
||||||
const response = await db.allDocs(
|
const response = await db.allDocs(
|
||||||
getDocParams(docType, null, {
|
getDocParams(docType, null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -34,19 +35,19 @@ async function getAllDocType(db, docType) {
|
||||||
return response.rows.map(row => row.doc)
|
return response.rows.map(row => row.doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.exportApps = async ctx => {
|
export async function exportApps(ctx: BBContext) {
|
||||||
if (env.SELF_HOSTED || !env.MULTI_TENANCY) {
|
if (env.SELF_HOSTED || !env.MULTI_TENANCY) {
|
||||||
ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.")
|
ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.")
|
||||||
}
|
}
|
||||||
const apps = await getAllApps({ all: true })
|
const apps = (await getAllApps({ all: true })) as App[]
|
||||||
const globalDBString = await sdk.backups.exportDB(getGlobalDBName(), {
|
const globalDBString = await sdk.backups.exportDB(dbCore.getGlobalDBName(), {
|
||||||
filter: doc => !doc._id.startsWith(DocumentType.USER),
|
filter: (doc: any) => !doc._id.startsWith(DocumentType.USER),
|
||||||
})
|
})
|
||||||
// only export the dev apps as they will be the latest, the user can republish the apps
|
// only export the dev apps as they will be the latest, the user can republish the apps
|
||||||
// in their self-hosted environment
|
// in their self-hosted environment
|
||||||
let appMetadata = apps
|
let appMetadata = apps
|
||||||
.filter(app => isDevAppID(app.appId || app._id))
|
.filter((app: App) => isDevAppID(app.appId || app._id))
|
||||||
.map(app => ({ appId: app.appId || app._id, name: app.name }))
|
.map((app: App) => ({ appId: (app.appId || app._id)!, name: app.name }))
|
||||||
const tmpPath = await sdk.backups.exportMultipleApps(
|
const tmpPath = await sdk.backups.exportMultipleApps(
|
||||||
appMetadata,
|
appMetadata,
|
||||||
globalDBString
|
globalDBString
|
||||||
|
@ -56,7 +57,7 @@ exports.exportApps = async ctx => {
|
||||||
ctx.body = streamFile(tmpPath)
|
ctx.body = streamFile(tmpPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasBeenImported() {
|
async function checkHasBeenImported() {
|
||||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -64,17 +65,17 @@ async function hasBeenImported() {
|
||||||
return apps.length !== 0
|
return apps.length !== 0
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.hasBeenImported = async ctx => {
|
export async function hasBeenImported(ctx: BBContext) {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
imported: await hasBeenImported(),
|
imported: await checkHasBeenImported(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.importApps = async ctx => {
|
export async function importApps(ctx: BBContext) {
|
||||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
||||||
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
||||||
}
|
}
|
||||||
const beenImported = await hasBeenImported()
|
const beenImported = await checkHasBeenImported()
|
||||||
if (beenImported || !ctx.request.files || !ctx.request.files.importFile) {
|
if (beenImported || !ctx.request.files || !ctx.request.files.importFile) {
|
||||||
ctx.throw(
|
ctx.throw(
|
||||||
400,
|
400,
|
||||||
|
@ -90,7 +91,7 @@ exports.importApps = async ctx => {
|
||||||
const globalDbImport = sdk.backups.getGlobalDBFile(tmpPath)
|
const globalDbImport = sdk.backups.getGlobalDBFile(tmpPath)
|
||||||
const appNames = sdk.backups.getListOfAppsInMulti(tmpPath)
|
const appNames = sdk.backups.getListOfAppsInMulti(tmpPath)
|
||||||
|
|
||||||
const globalDb = getGlobalDB()
|
const globalDb = tenancy.getGlobalDB()
|
||||||
// load the global db first
|
// load the global db first
|
||||||
await globalDb.load(stringToReadStream(globalDbImport))
|
await globalDb.load(stringToReadStream(globalDbImport))
|
||||||
for (let appName of appNames) {
|
for (let appName of appNames) {
|
|
@ -1,15 +1,16 @@
|
||||||
const { MetadataTypes } = require("../../constants")
|
import { MetadataTypes } from "../../constants"
|
||||||
const { generateMetadataID } = require("../../db/utils")
|
import { generateMetadataID } from "../../db/utils"
|
||||||
const { saveEntityMetadata, deleteEntityMetadata } = require("../../utilities")
|
import { saveEntityMetadata, deleteEntityMetadata } from "../../utilities"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { context } from "@budibase/backend-core"
|
||||||
|
import { BBContext } from "@budibase/types"
|
||||||
|
|
||||||
exports.getTypes = async ctx => {
|
export async function getTypes(ctx: BBContext) {
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
types: MetadataTypes,
|
types: MetadataTypes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.saveMetadata = async ctx => {
|
export async function saveMetadata(ctx: BBContext) {
|
||||||
const { type, entityId } = ctx.params
|
const { type, entityId } = ctx.params
|
||||||
if (type === MetadataTypes.AUTOMATION_TEST_HISTORY) {
|
if (type === MetadataTypes.AUTOMATION_TEST_HISTORY) {
|
||||||
ctx.throw(400, "Cannot save automation history type")
|
ctx.throw(400, "Cannot save automation history type")
|
||||||
|
@ -17,7 +18,7 @@ exports.saveMetadata = async ctx => {
|
||||||
ctx.body = await saveEntityMetadata(type, entityId, ctx.request.body)
|
ctx.body = await saveEntityMetadata(type, entityId, ctx.request.body)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.deleteMetadata = async ctx => {
|
export async function deleteMetadata(ctx: BBContext) {
|
||||||
const { type, entityId } = ctx.params
|
const { type, entityId } = ctx.params
|
||||||
await deleteEntityMetadata(type, entityId)
|
await deleteEntityMetadata(type, entityId)
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
@ -25,13 +26,13 @@ exports.deleteMetadata = async ctx => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getMetadata = async ctx => {
|
export async function getMetadata(ctx: BBContext) {
|
||||||
const { type, entityId } = ctx.params
|
const { type, entityId } = ctx.params
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const id = generateMetadataID(type, entityId)
|
const id = generateMetadataID(type, entityId)
|
||||||
try {
|
try {
|
||||||
ctx.body = await db.get(id)
|
ctx.body = await db.get(id)
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
if (err.status === 404) {
|
if (err.status === 404) {
|
||||||
ctx.body = {}
|
ctx.body = {}
|
||||||
} else {
|
} else {
|
|
@ -1,18 +1,11 @@
|
||||||
const { getBuiltinPermissions } = require("@budibase/backend-core/permissions")
|
import { permissions, roles, context } from "@budibase/backend-core"
|
||||||
const {
|
import { getRoleParams } from "../../db/utils"
|
||||||
isBuiltin,
|
import {
|
||||||
getDBRoleID,
|
|
||||||
getExternalRoleID,
|
|
||||||
getBuiltinRoles,
|
|
||||||
checkForRoleResourceArray,
|
|
||||||
} = require("@budibase/backend-core/roles")
|
|
||||||
const { getRoleParams } = require("../../db/utils")
|
|
||||||
const {
|
|
||||||
CURRENTLY_SUPPORTED_LEVELS,
|
CURRENTLY_SUPPORTED_LEVELS,
|
||||||
getBasePermissions,
|
getBasePermissions,
|
||||||
} = require("../../utilities/security")
|
} from "../../utilities/security"
|
||||||
const { removeFromArray } = require("../../utilities")
|
import { removeFromArray } from "../../utilities"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { BBContext, Database, Role } from "@budibase/types"
|
||||||
|
|
||||||
const PermissionUpdateType = {
|
const PermissionUpdateType = {
|
||||||
REMOVE: "remove",
|
REMOVE: "remove",
|
||||||
|
@ -22,7 +15,7 @@ const PermissionUpdateType = {
|
||||||
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
||||||
|
|
||||||
// utility function to stop this repetition - permissions always stored under roles
|
// utility function to stop this repetition - permissions always stored under roles
|
||||||
async function getAllDBRoles(db) {
|
async function getAllDBRoles(db: Database) {
|
||||||
const body = await db.allDocs(
|
const body = await db.allDocs(
|
||||||
getRoleParams(null, {
|
getRoleParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
|
@ -32,21 +25,25 @@ async function getAllDBRoles(db) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updatePermissionOnRole(
|
async function updatePermissionOnRole(
|
||||||
appId,
|
appId: string,
|
||||||
{ roleId, resourceId, level },
|
{
|
||||||
updateType
|
roleId,
|
||||||
|
resourceId,
|
||||||
|
level,
|
||||||
|
}: { roleId: string; resourceId: string; level: string },
|
||||||
|
updateType: string
|
||||||
) {
|
) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const remove = updateType === PermissionUpdateType.REMOVE
|
const remove = updateType === PermissionUpdateType.REMOVE
|
||||||
const isABuiltin = isBuiltin(roleId)
|
const isABuiltin = roles.isBuiltin(roleId)
|
||||||
const dbRoleId = getDBRoleID(roleId)
|
const dbRoleId = roles.getDBRoleID(roleId)
|
||||||
const dbRoles = await getAllDBRoles(db)
|
const dbRoles = await getAllDBRoles(db)
|
||||||
const docUpdates = []
|
const docUpdates = []
|
||||||
|
|
||||||
// the permission is for a built in, make sure it exists
|
// the permission is for a built in, make sure it exists
|
||||||
if (isABuiltin && !dbRoles.some(role => role._id === dbRoleId)) {
|
if (isABuiltin && !dbRoles.some(role => role._id === dbRoleId)) {
|
||||||
const builtin = getBuiltinRoles()[roleId]
|
const builtin = roles.getBuiltinRoles()[roleId]
|
||||||
builtin._id = getDBRoleID(builtin._id)
|
builtin._id = roles.getDBRoleID(builtin._id)
|
||||||
dbRoles.push(builtin)
|
dbRoles.push(builtin)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,41 +87,44 @@ async function updatePermissionOnRole(
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.bulkDocs(docUpdates)
|
const response = await db.bulkDocs(docUpdates)
|
||||||
return response.map(resp => {
|
return response.map((resp: any) => {
|
||||||
resp._id = getExternalRoleID(resp.id)
|
resp._id = roles.getExternalRoleID(resp.id)
|
||||||
delete resp.id
|
delete resp.id
|
||||||
return resp
|
return resp
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchBuiltin = function (ctx) {
|
export function fetchBuiltin(ctx: BBContext) {
|
||||||
ctx.body = Object.values(getBuiltinPermissions())
|
ctx.body = Object.values(permissions.getBuiltinPermissions())
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchLevels = function (ctx) {
|
export function fetchLevels(ctx: BBContext) {
|
||||||
// for now only provide the read/write perms externally
|
// for now only provide the read/write perms externally
|
||||||
ctx.body = SUPPORTED_LEVELS
|
ctx.body = SUPPORTED_LEVELS
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
export async function fetch(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const roles = await getAllDBRoles(db)
|
const dbRoles: Role[] = await getAllDBRoles(db)
|
||||||
let permissions = {}
|
let permissions: any = {}
|
||||||
// create an object with structure role ID -> resource ID -> level
|
// create an object with structure role ID -> resource ID -> level
|
||||||
for (let role of roles) {
|
for (let role of dbRoles) {
|
||||||
if (!role.permissions) {
|
if (!role.permissions) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const roleId = getExternalRoleID(role._id)
|
const roleId = roles.getExternalRoleID(role._id)
|
||||||
|
if (!roleId) {
|
||||||
|
ctx.throw(400, "Unable to retrieve role")
|
||||||
|
}
|
||||||
for (let [resource, levelArr] of Object.entries(role.permissions)) {
|
for (let [resource, levelArr] of Object.entries(role.permissions)) {
|
||||||
const levels = Array.isArray(levelArr) ? [levelArr] : levelArr
|
const levels: string[] = Array.isArray(levelArr) ? levelArr : [levelArr]
|
||||||
const perms = {}
|
const perms: Record<string, string> = {}
|
||||||
levels.forEach(level => (perms[level] = roleId))
|
levels.forEach(level => (perms[level] = roleId!))
|
||||||
permissions[resource] = perms
|
permissions[resource] = perms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// apply the base permissions
|
// apply the base permissions
|
||||||
const finalPermissions = {}
|
const finalPermissions: Record<string, Record<string, string>> = {}
|
||||||
for (let [resource, permission] of Object.entries(permissions)) {
|
for (let [resource, permission] of Object.entries(permissions)) {
|
||||||
const basePerms = getBasePermissions(resource)
|
const basePerms = getBasePermissions(resource)
|
||||||
finalPermissions[resource] = Object.assign(basePerms, permission)
|
finalPermissions[resource] = Object.assign(basePerms, permission)
|
||||||
|
@ -132,33 +132,36 @@ exports.fetch = async function (ctx) {
|
||||||
ctx.body = finalPermissions
|
ctx.body = finalPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getResourcePerms = async function (ctx) {
|
export async function getResourcePerms(ctx: BBContext) {
|
||||||
const resourceId = ctx.params.resourceId
|
const resourceId = ctx.params.resourceId
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const body = await db.allDocs(
|
const body = await db.allDocs(
|
||||||
getRoleParams(null, {
|
getRoleParams(null, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const roles = body.rows.map(row => row.doc)
|
const rolesList = body.rows.map(row => row.doc)
|
||||||
let permissions = {}
|
let permissions: Record<string, string> = {}
|
||||||
for (let level of SUPPORTED_LEVELS) {
|
for (let level of SUPPORTED_LEVELS) {
|
||||||
// update the various roleIds in the resource permissions
|
// update the various roleIds in the resource permissions
|
||||||
for (let role of roles) {
|
for (let role of rolesList) {
|
||||||
const rolePerms = checkForRoleResourceArray(role.permissions, resourceId)
|
const rolePerms = roles.checkForRoleResourceArray(
|
||||||
|
role.permissions,
|
||||||
|
resourceId
|
||||||
|
)
|
||||||
if (
|
if (
|
||||||
rolePerms &&
|
rolePerms &&
|
||||||
rolePerms[resourceId] &&
|
rolePerms[resourceId] &&
|
||||||
rolePerms[resourceId].indexOf(level) !== -1
|
rolePerms[resourceId].indexOf(level) !== -1
|
||||||
) {
|
) {
|
||||||
permissions[level] = getExternalRoleID(role._id)
|
permissions[level] = roles.getExternalRoleID(role._id)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.body = Object.assign(getBasePermissions(resourceId), permissions)
|
ctx.body = Object.assign(getBasePermissions(resourceId), permissions)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addPermission = async function (ctx) {
|
export async function addPermission(ctx: BBContext) {
|
||||||
ctx.body = await updatePermissionOnRole(
|
ctx.body = await updatePermissionOnRole(
|
||||||
ctx.appId,
|
ctx.appId,
|
||||||
ctx.params,
|
ctx.params,
|
||||||
|
@ -166,7 +169,7 @@ exports.addPermission = async function (ctx) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.removePermission = async function (ctx) {
|
export async function removePermission(ctx: BBContext) {
|
||||||
ctx.body = await updatePermissionOnRole(
|
ctx.body = await updatePermissionOnRole(
|
||||||
ctx.appId,
|
ctx.appId,
|
||||||
ctx.params,
|
ctx.params,
|
|
@ -5,8 +5,7 @@ import { OpenAPI2 } from "./sources/openapi2"
|
||||||
import { OpenAPI3 } from "./sources/openapi3"
|
import { OpenAPI3 } from "./sources/openapi3"
|
||||||
import { Curl } from "./sources/curl"
|
import { Curl } from "./sources/curl"
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { getAppDB } from "@budibase/backend-core/context"
|
import { events, context } from "@budibase/backend-core"
|
||||||
import { events } from "@budibase/backend-core"
|
|
||||||
import { Datasource, Query } from "@budibase/types"
|
import { Datasource, Query } from "@budibase/types"
|
||||||
|
|
||||||
interface ImportResult {
|
interface ImportResult {
|
||||||
|
@ -59,7 +58,7 @@ export class RestImporter {
|
||||||
})
|
})
|
||||||
|
|
||||||
// persist queries
|
// persist queries
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const response = await db.bulkDocs(queries)
|
const response = await db.bulkDocs(queries)
|
||||||
|
|
||||||
// create index to seperate queries and errors
|
// create index to seperate queries and errors
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
const { joiValidator } = require("@budibase/backend-core/auth")
|
import { auth } from "@budibase/backend-core"
|
||||||
const Joi = require("joi")
|
import Joi from "joi"
|
||||||
|
|
||||||
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
||||||
|
|
||||||
exports.queryValidation = () => {
|
export function queryValidation() {
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
_id: Joi.string(),
|
_id: Joi.string(),
|
||||||
_rev: Joi.string(),
|
_rev: Joi.string(),
|
||||||
|
@ -25,14 +25,14 @@ exports.queryValidation = () => {
|
||||||
}).unknown(true)
|
}).unknown(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.generateQueryValidation = () => {
|
export function generateQueryValidation() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return joiValidator.body(exports.queryValidation())
|
return auth.joiValidator.body(queryValidation())
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.generateQueryPreviewValidation = () => {
|
export function generateQueryPreviewValidation() {
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return joiValidator.body(Joi.object({
|
return auth.joiValidator.body(Joi.object({
|
||||||
_id: OPTIONAL_STRING,
|
_id: OPTIONAL_STRING,
|
||||||
_rev: OPTIONAL_STRING,
|
_rev: OPTIONAL_STRING,
|
||||||
readable: Joi.boolean().optional(),
|
readable: Joi.boolean().optional(),
|
|
@ -1,23 +1,21 @@
|
||||||
const {
|
import { roles, context, events } from "@budibase/backend-core"
|
||||||
Role,
|
import {
|
||||||
getRole,
|
|
||||||
isBuiltin,
|
|
||||||
getAllRoles,
|
|
||||||
} = require("@budibase/backend-core/roles")
|
|
||||||
const {
|
|
||||||
generateRoleID,
|
generateRoleID,
|
||||||
getUserMetadataParams,
|
getUserMetadataParams,
|
||||||
InternalTables,
|
InternalTables,
|
||||||
} = require("../../db/utils")
|
} from "../../db/utils"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { BBContext, Database } from "@budibase/types"
|
||||||
const { events } = require("@budibase/backend-core")
|
|
||||||
|
|
||||||
const UpdateRolesOptions = {
|
const UpdateRolesOptions = {
|
||||||
CREATED: "created",
|
CREATED: "created",
|
||||||
REMOVED: "removed",
|
REMOVED: "removed",
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
async function updateRolesOnUserTable(
|
||||||
|
db: Database,
|
||||||
|
roleId: string,
|
||||||
|
updateOption: string
|
||||||
|
) {
|
||||||
const table = await db.get(InternalTables.USER_METADATA)
|
const table = await db.get(InternalTables.USER_METADATA)
|
||||||
const schema = table.schema
|
const schema = table.schema
|
||||||
const remove = updateOption === UpdateRolesOptions.REMOVED
|
const remove = updateOption === UpdateRolesOptions.REMOVED
|
||||||
|
@ -40,27 +38,25 @@ async function updateRolesOnUserTable(db, roleId, updateOption) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
export async function fetch(ctx: BBContext) {
|
||||||
ctx.body = await getAllRoles()
|
ctx.body = await roles.getAllRoles()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async function (ctx) {
|
export async function find(ctx: BBContext) {
|
||||||
ctx.body = await getRole(ctx.params.roleId)
|
ctx.body = await roles.getRole(ctx.params.roleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async function (ctx) {
|
export async function save(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
let { _id, name, inherits, permissionId } = ctx.request.body
|
let { _id, name, inherits, permissionId } = ctx.request.body
|
||||||
let isCreate = false
|
let isCreate = false
|
||||||
if (!_id) {
|
if (!_id) {
|
||||||
_id = generateRoleID()
|
_id = generateRoleID()
|
||||||
isCreate = true
|
isCreate = true
|
||||||
} else if (isBuiltin(_id)) {
|
} else if (roles.isBuiltin(_id)) {
|
||||||
ctx.throw(400, "Cannot update builtin roles.")
|
ctx.throw(400, "Cannot update builtin roles.")
|
||||||
}
|
}
|
||||||
const role = new Role(_id, name)
|
const role = new roles.Role(_id, name, permissionId).addInheritance(inherits)
|
||||||
.addPermission(permissionId)
|
|
||||||
.addInheritance(inherits)
|
|
||||||
if (ctx.request.body._rev) {
|
if (ctx.request.body._rev) {
|
||||||
role._rev = ctx.request.body._rev
|
role._rev = ctx.request.body._rev
|
||||||
}
|
}
|
||||||
|
@ -76,17 +72,17 @@ exports.save = async function (ctx) {
|
||||||
ctx.message = `Role '${role.name}' created successfully.`
|
ctx.message = `Role '${role.name}' created successfully.`
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async function (ctx) {
|
export async function destroy(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const roleId = ctx.params.roleId
|
const roleId = ctx.params.roleId
|
||||||
const role = await db.get(roleId)
|
const role = await db.get(roleId)
|
||||||
if (isBuiltin(roleId)) {
|
if (roles.isBuiltin(roleId)) {
|
||||||
ctx.throw(400, "Cannot delete builtin role.")
|
ctx.throw(400, "Cannot delete builtin role.")
|
||||||
}
|
}
|
||||||
// first check no users actively attached to role
|
// first check no users actively attached to role
|
||||||
const users = (
|
const users = (
|
||||||
await db.allDocs(
|
await db.allDocs(
|
||||||
getUserMetadataParams(null, {
|
getUserMetadataParams(undefined, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
|
@ -1,40 +1,41 @@
|
||||||
const { getRoutingInfo } = require("../../utilities/routing")
|
import { getRoutingInfo } from "../../utilities/routing"
|
||||||
const {
|
import { roles } from "@budibase/backend-core"
|
||||||
getUserRoleHierarchy,
|
import { BBContext } from "@budibase/types"
|
||||||
BUILTIN_ROLE_IDS,
|
|
||||||
} = require("@budibase/backend-core/roles")
|
|
||||||
|
|
||||||
const URL_SEPARATOR = "/"
|
const URL_SEPARATOR = "/"
|
||||||
|
|
||||||
function Routing() {
|
class Routing {
|
||||||
this.json = {}
|
json: any
|
||||||
}
|
constructor() {
|
||||||
|
this.json = {}
|
||||||
Routing.prototype.getTopLevel = function (fullpath) {
|
|
||||||
if (fullpath.charAt(0) !== URL_SEPARATOR) {
|
|
||||||
fullpath = URL_SEPARATOR + fullpath
|
|
||||||
}
|
}
|
||||||
// replace the first value with the home route
|
|
||||||
return URL_SEPARATOR + fullpath.split(URL_SEPARATOR)[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
Routing.prototype.getScreensProp = function (fullpath) {
|
getTopLevel(fullpath: string) {
|
||||||
const topLevel = this.getTopLevel(fullpath)
|
if (fullpath.charAt(0) !== URL_SEPARATOR) {
|
||||||
if (!this.json[topLevel]) {
|
fullpath = URL_SEPARATOR + fullpath
|
||||||
this.json[topLevel] = {
|
|
||||||
subpaths: {},
|
|
||||||
}
|
}
|
||||||
|
// replace the first value with the home route
|
||||||
|
return URL_SEPARATOR + fullpath.split(URL_SEPARATOR)[1]
|
||||||
}
|
}
|
||||||
if (!this.json[topLevel].subpaths[fullpath]) {
|
|
||||||
this.json[topLevel].subpaths[fullpath] = {
|
|
||||||
screens: {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.json[topLevel].subpaths[fullpath].screens
|
|
||||||
}
|
|
||||||
|
|
||||||
Routing.prototype.addScreenId = function (fullpath, roleId, screenId) {
|
getScreensProp(fullpath: string) {
|
||||||
this.getScreensProp(fullpath)[roleId] = screenId
|
const topLevel = this.getTopLevel(fullpath)
|
||||||
|
if (!this.json[topLevel]) {
|
||||||
|
this.json[topLevel] = {
|
||||||
|
subpaths: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.json[topLevel].subpaths[fullpath]) {
|
||||||
|
this.json[topLevel].subpaths[fullpath] = {
|
||||||
|
screens: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.json[topLevel].subpaths[fullpath].screens
|
||||||
|
}
|
||||||
|
|
||||||
|
addScreenId(fullpath: string, roleId: string, screenId: string) {
|
||||||
|
this.getScreensProp(fullpath)[roleId] = screenId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,26 +56,28 @@ async function getRoutingStructure() {
|
||||||
return { routes: routing.json }
|
return { routes: routing.json }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
export async function fetch(ctx: BBContext) {
|
||||||
ctx.body = await getRoutingStructure()
|
ctx.body = await getRoutingStructure()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.clientFetch = async ctx => {
|
export async function clientFetch(ctx: BBContext) {
|
||||||
const routing = await getRoutingStructure()
|
const routing = await getRoutingStructure()
|
||||||
let roleId = ctx.user.role._id
|
let roleId = ctx.user?.role?._id
|
||||||
const roleIds = await getUserRoleHierarchy(roleId)
|
const roleIds = (await roles.getUserRoleHierarchy(roleId, {
|
||||||
for (let topLevel of Object.values(routing.routes)) {
|
idOnly: true,
|
||||||
|
})) as string[]
|
||||||
|
for (let topLevel of Object.values(routing.routes) as any) {
|
||||||
for (let subpathKey of Object.keys(topLevel.subpaths)) {
|
for (let subpathKey of Object.keys(topLevel.subpaths)) {
|
||||||
let found = false
|
let found = false
|
||||||
const subpath = topLevel.subpaths[subpathKey]
|
const subpath = topLevel.subpaths[subpathKey]
|
||||||
const roleOptions = Object.keys(subpath.screens)
|
const roleOptions = Object.keys(subpath.screens)
|
||||||
if (roleOptions.length === 1 && !roleOptions[0]) {
|
if (roleOptions.length === 1 && !roleOptions[0]) {
|
||||||
subpath.screenId = subpath.screens[roleOptions[0]]
|
subpath.screenId = subpath.screens[roleOptions[0]]
|
||||||
subpath.roleId = BUILTIN_ROLE_IDS.BASIC
|
subpath.roleId = roles.BUILTIN_ROLE_IDS.BASIC
|
||||||
found = true
|
found = true
|
||||||
} else {
|
} else {
|
||||||
for (let roleId of roleIds) {
|
for (let roleId of roleIds) {
|
||||||
if (roleOptions.indexOf(roleId) !== -1) {
|
if (roleId && roleOptions.indexOf(roleId) !== -1) {
|
||||||
subpath.screenId = subpath.screens[roleId]
|
subpath.screenId = subpath.screens[roleId]
|
||||||
subpath.roleId = roleId
|
subpath.roleId = roleId
|
||||||
found = true
|
found = true
|
|
@ -1,4 +1,6 @@
|
||||||
exports.csv = function (headers, rows) {
|
import { Row } from "@budibase/types"
|
||||||
|
|
||||||
|
export function csv(headers: string[], rows: Row[]) {
|
||||||
let csv = headers.map(key => `"${key}"`).join(",")
|
let csv = headers.map(key => `"${key}"`).join(",")
|
||||||
|
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
|
@ -16,11 +18,11 @@ exports.csv = function (headers, rows) {
|
||||||
return csv
|
return csv
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.json = function (headers, rows) {
|
export function json(headers: string[], rows: Row[]) {
|
||||||
return JSON.stringify(rows, undefined, 2)
|
return JSON.stringify(rows, undefined, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.ExportFormats = {
|
export const ExportFormats = {
|
||||||
CSV: "csv",
|
CSV: "csv",
|
||||||
JSON: "json",
|
JSON: "json",
|
||||||
}
|
}
|
|
@ -1,21 +1,29 @@
|
||||||
const viewTemplate = require("./viewBuilder")
|
import viewTemplate from "./viewBuilder"
|
||||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
import { apiFileReturn } from "../../../utilities/fileSystem"
|
||||||
const exporters = require("./exporters")
|
import * as exporters from "./exporters"
|
||||||
const { saveView, getView, getViews, deleteView } = require("./utils")
|
import { deleteView, getView, getViews, saveView } from "./utils"
|
||||||
const { fetchView } = require("../row")
|
import { fetchView } from "../row"
|
||||||
const { FieldTypes } = require("../../../constants")
|
import { FieldTypes } from "../../../constants"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { context, events } from "@budibase/backend-core"
|
||||||
const { events } = require("@budibase/backend-core")
|
import { DocumentType } from "../../../db/utils"
|
||||||
const { DocumentType } = require("../../../db/utils")
|
import sdk from "../../../sdk"
|
||||||
const { cloneDeep, isEqual } = require("lodash")
|
import {
|
||||||
const sdk = require("../../../sdk")
|
BBContext,
|
||||||
|
Row,
|
||||||
|
Table,
|
||||||
|
TableExportFormat,
|
||||||
|
TableSchema,
|
||||||
|
View,
|
||||||
|
} from "@budibase/types"
|
||||||
|
|
||||||
exports.fetch = async ctx => {
|
const { cloneDeep, isEqual } = require("lodash")
|
||||||
|
|
||||||
|
export async function fetch(ctx: BBContext) {
|
||||||
ctx.body = await getViews()
|
ctx.body = await getViews()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async ctx => {
|
export async function save(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const { originalName, ...viewToSave } = ctx.request.body
|
const { originalName, ...viewToSave } = ctx.request.body
|
||||||
const view = viewTemplate(viewToSave)
|
const view = viewTemplate(viewToSave)
|
||||||
const viewName = viewToSave.name
|
const viewName = viewToSave.name
|
||||||
|
@ -47,7 +55,7 @@ exports.save = async ctx => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculationEvents = async (existingView, newView) => {
|
export async function calculationEvents(existingView: View, newView: View) {
|
||||||
const existingCalculation = existingView && existingView.calculation
|
const existingCalculation = existingView && existingView.calculation
|
||||||
const newCalculation = newView && newView.calculation
|
const newCalculation = newView && newView.calculation
|
||||||
|
|
||||||
|
@ -68,7 +76,7 @@ const calculationEvents = async (existingView, newView) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterEvents = async (existingView, newView) => {
|
export async function filterEvents(existingView: View, newView: View) {
|
||||||
const hasExistingFilters = !!(
|
const hasExistingFilters = !!(
|
||||||
existingView &&
|
existingView &&
|
||||||
existingView.filters &&
|
existingView.filters &&
|
||||||
|
@ -93,7 +101,7 @@ const filterEvents = async (existingView, newView) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleViewEvents = async (existingView, newView) => {
|
async function handleViewEvents(existingView: View, newView: View) {
|
||||||
if (!existingView) {
|
if (!existingView) {
|
||||||
await events.view.created(newView)
|
await events.view.created(newView)
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,8 +111,8 @@ const handleViewEvents = async (existingView, newView) => {
|
||||||
await filterEvents(existingView, newView)
|
await filterEvents(existingView, newView)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.destroy = async ctx => {
|
export async function destroy(ctx: BBContext) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const viewName = decodeURI(ctx.params.viewName)
|
const viewName = decodeURI(ctx.params.viewName)
|
||||||
const view = await deleteView(viewName)
|
const view = await deleteView(viewName)
|
||||||
const table = await db.get(view.meta.tableId)
|
const table = await db.get(view.meta.tableId)
|
||||||
|
@ -115,11 +123,11 @@ exports.destroy = async ctx => {
|
||||||
ctx.body = view
|
ctx.body = view
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.exportView = async ctx => {
|
export async function exportView(ctx: BBContext) {
|
||||||
const viewName = decodeURI(ctx.query.view)
|
const viewName = decodeURI(ctx.query.view as string)
|
||||||
const view = await getView(viewName)
|
const view = await getView(viewName)
|
||||||
|
|
||||||
const format = ctx.query.format
|
const format = ctx.query.format as string
|
||||||
if (!format || !Object.values(exporters.ExportFormats).includes(format)) {
|
if (!format || !Object.values(exporters.ExportFormats).includes(format)) {
|
||||||
ctx.throw(400, "Format must be specified, either csv or json")
|
ctx.throw(400, "Format must be specified, either csv or json")
|
||||||
}
|
}
|
||||||
|
@ -130,6 +138,7 @@ exports.exportView = async ctx => {
|
||||||
ctx.query = {
|
ctx.query = {
|
||||||
group: view.meta.groupBy,
|
group: view.meta.groupBy,
|
||||||
calculation: view.meta.calculation,
|
calculation: view.meta.calculation,
|
||||||
|
// @ts-ignore
|
||||||
stats: !!view.meta.field,
|
stats: !!view.meta.field,
|
||||||
field: view.meta.field,
|
field: view.meta.field,
|
||||||
}
|
}
|
||||||
|
@ -140,11 +149,11 @@ exports.exportView = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await fetchView(ctx)
|
await fetchView(ctx)
|
||||||
let rows = ctx.body
|
let rows = ctx.body as Row[]
|
||||||
|
|
||||||
let schema = view && view.meta && view.meta.schema
|
let schema: TableSchema = view && view.meta && view.meta.schema
|
||||||
const tableId = ctx.params.tableId || view.meta.tableId
|
const tableId = ctx.params.tableId || view.meta.tableId
|
||||||
const table = await sdk.tables.getTable(tableId)
|
const table: Table = await sdk.tables.getTable(tableId)
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
schema = table.schema
|
schema = table.schema
|
||||||
}
|
}
|
||||||
|
@ -175,15 +184,15 @@ exports.exportView = async ctx => {
|
||||||
|
|
||||||
// Export part
|
// Export part
|
||||||
let headers = Object.keys(schema)
|
let headers = Object.keys(schema)
|
||||||
const exporter = exporters[format]
|
const exporter = format === "csv" ? exporters.csv : exporters.json
|
||||||
const filename = `${viewName}.${format}`
|
const filename = `${viewName}.${format}`
|
||||||
// send down the file
|
// send down the file
|
||||||
ctx.attachment(filename)
|
ctx.attachment(filename)
|
||||||
ctx.body = apiFileReturn(exporter(headers, rows))
|
ctx.body = apiFileReturn(exporter(headers, rows))
|
||||||
|
|
||||||
if (viewName.startsWith(DocumentType.TABLE)) {
|
if (viewName.startsWith(DocumentType.TABLE)) {
|
||||||
await events.table.exported(table, format)
|
await events.table.exported(table, format as TableExportFormat)
|
||||||
} else {
|
} else {
|
||||||
await events.view.exported(table, format)
|
await events.view.exported(table, format as TableExportFormat)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,16 +1,17 @@
|
||||||
const {
|
import {
|
||||||
ViewName,
|
ViewName,
|
||||||
generateMemoryViewID,
|
generateMemoryViewID,
|
||||||
getMemoryViewParams,
|
getMemoryViewParams,
|
||||||
DocumentType,
|
DocumentType,
|
||||||
SEPARATOR,
|
SEPARATOR,
|
||||||
} = require("../../../db/utils")
|
} from "../../../db/utils"
|
||||||
const env = require("../../../environment")
|
import env from "../../../environment"
|
||||||
const { getAppDB } = require("@budibase/backend-core/context")
|
import { context } from "@budibase/backend-core"
|
||||||
const viewBuilder = require("./viewBuilder")
|
import viewBuilder from "./viewBuilder"
|
||||||
|
import { Database } from "@budibase/types"
|
||||||
|
|
||||||
exports.getView = async viewName => {
|
export async function getView(viewName: string) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
if (env.SELF_HOSTED) {
|
if (env.SELF_HOSTED) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
return designDoc.views[viewName]
|
return designDoc.views[viewName]
|
||||||
|
@ -23,7 +24,7 @@ exports.getView = async viewName => {
|
||||||
try {
|
try {
|
||||||
const viewDoc = await db.get(generateMemoryViewID(viewName))
|
const viewDoc = await db.get(generateMemoryViewID(viewName))
|
||||||
return viewDoc.view
|
return viewDoc.view
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
// Return null when PouchDB doesn't found the view
|
// Return null when PouchDB doesn't found the view
|
||||||
if (err.status === 404) {
|
if (err.status === 404) {
|
||||||
return null
|
return null
|
||||||
|
@ -34,14 +35,15 @@ exports.getView = async viewName => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getViews = async () => {
|
export async function getViews() {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
const response = []
|
const response = []
|
||||||
if (env.SELF_HOSTED) {
|
if (env.SELF_HOSTED) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
for (let name of Object.keys(designDoc.views)) {
|
for (let name of Object.keys(designDoc.views)) {
|
||||||
// Only return custom views, not built ins
|
// Only return custom views, not built ins
|
||||||
if (Object.values(ViewName).indexOf(name) !== -1) {
|
const viewNames = Object.values(ViewName) as string[]
|
||||||
|
if (viewNames.indexOf(name) !== -1) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
response.push({
|
response.push({
|
||||||
|
@ -67,8 +69,12 @@ exports.getViews = async () => {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.saveView = async (originalName, viewName, viewTemplate) => {
|
export async function saveView(
|
||||||
const db = getAppDB()
|
originalName: string,
|
||||||
|
viewName: string,
|
||||||
|
viewTemplate: any
|
||||||
|
) {
|
||||||
|
const db = context.getAppDB()
|
||||||
if (env.SELF_HOSTED) {
|
if (env.SELF_HOSTED) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
designDoc.views = {
|
designDoc.views = {
|
||||||
|
@ -83,7 +89,7 @@ exports.saveView = async (originalName, viewName, viewTemplate) => {
|
||||||
} else {
|
} else {
|
||||||
const id = generateMemoryViewID(viewName)
|
const id = generateMemoryViewID(viewName)
|
||||||
const originalId = originalName ? generateMemoryViewID(originalName) : null
|
const originalId = originalName ? generateMemoryViewID(originalName) : null
|
||||||
const viewDoc = {
|
const viewDoc: any = {
|
||||||
_id: id,
|
_id: id,
|
||||||
view: viewTemplate,
|
view: viewTemplate,
|
||||||
name: viewName,
|
name: viewName,
|
||||||
|
@ -105,8 +111,8 @@ exports.saveView = async (originalName, viewName, viewTemplate) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.deleteView = async viewName => {
|
export async function deleteView(viewName: string) {
|
||||||
const db = getAppDB()
|
const db = context.getAppDB()
|
||||||
if (env.SELF_HOSTED) {
|
if (env.SELF_HOSTED) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
const view = designDoc.views[viewName]
|
const view = designDoc.views[viewName]
|
||||||
|
@ -121,7 +127,7 @@ exports.deleteView = async viewName => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.migrateToInMemoryView = async (db, viewName) => {
|
export async function migrateToInMemoryView(db: Database, viewName: string) {
|
||||||
// delete the view initially
|
// delete the view initially
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
// run the view back through the view builder to update it
|
// run the view back through the view builder to update it
|
||||||
|
@ -131,7 +137,7 @@ exports.migrateToInMemoryView = async (db, viewName) => {
|
||||||
await exports.saveView(db, null, viewName, view)
|
await exports.saveView(db, null, viewName, view)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.migrateToDesignView = async (db, viewName) => {
|
export async function migrateToDesignView(db: Database, viewName: string) {
|
||||||
let view = await db.get(generateMemoryViewID(viewName))
|
let view = await db.get(generateMemoryViewID(viewName))
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
designDoc.views[viewName] = viewBuilder(view.view.meta)
|
designDoc.views[viewName] = viewBuilder(view.view.meta)
|
||||||
|
@ -139,7 +145,7 @@ exports.migrateToDesignView = async (db, viewName) => {
|
||||||
await db.remove(view._id, view._rev)
|
await db.remove(view._id, view._rev)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getFromDesignDoc = async (db, viewName) => {
|
export async function getFromDesignDoc(db: Database, viewName: string) {
|
||||||
const designDoc = await db.get("_design/database")
|
const designDoc = await db.get("_design/database")
|
||||||
let view = designDoc.views[viewName]
|
let view = designDoc.views[viewName]
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
|
@ -148,7 +154,7 @@ exports.getFromDesignDoc = async (db, viewName) => {
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getFromMemoryDoc = async (db, viewName) => {
|
export async function getFromMemoryDoc(db: Database, viewName: string) {
|
||||||
let view = await db.get(generateMemoryViewID(viewName))
|
let view = await db.get(generateMemoryViewID(viewName))
|
||||||
if (view) {
|
if (view) {
|
||||||
view = view.view
|
view = view.view
|
|
@ -35,6 +35,7 @@ export interface Automation extends Document {
|
||||||
trigger: AutomationTrigger
|
trigger: AutomationTrigger
|
||||||
}
|
}
|
||||||
appId: string
|
appId: string
|
||||||
|
live?: boolean
|
||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ export interface ContextUser extends Omit<User, "roles"> {
|
||||||
|
|
||||||
export interface BBRequest extends Request {
|
export interface BBRequest extends Request {
|
||||||
body: any
|
body: any
|
||||||
|
files?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BBContext extends Context {
|
export interface BBContext extends Context {
|
||||||
|
|
Loading…
Reference in a new issue