1
0
Fork 0
mirror of synced 2024-07-15 03:05:57 +12:00

More controller typescript conversions.

This commit is contained in:
mike12345567 2022-11-22 16:52:25 +00:00
parent 8a4da7d4ce
commit 92210144ff
16 changed files with 284 additions and 261 deletions

View file

@ -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()}`
} }

View file

@ -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

View file

@ -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)
} }

View file

@ -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)

View file

@ -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) {

View file

@ -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 {

View file

@ -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,

View file

@ -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

View file

@ -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(),

View file

@ -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,
}) })
) )

View file

@ -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

View file

@ -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",
} }

View file

@ -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)
} }
} }

View file

@ -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

View file

@ -35,6 +35,7 @@ export interface Automation extends Document {
trigger: AutomationTrigger trigger: AutomationTrigger
} }
appId: string appId: string
live?: boolean
name: string name: string
} }

View file

@ -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 {