Main body of work, refactoring most usages.
This commit is contained in:
parent
d8ab715267
commit
d2fe119d90
|
@ -0,0 +1,15 @@
|
|||
const {
|
||||
getAppDB,
|
||||
getDevAppDB,
|
||||
getProdAppDB,
|
||||
getAppId,
|
||||
updateAppId,
|
||||
} = require("./src/tenancy/context")
|
||||
|
||||
module.exports = {
|
||||
getAppDB,
|
||||
getDevAppDB,
|
||||
getProdAppDB,
|
||||
getAppId,
|
||||
updateAppId,
|
||||
}
|
|
@ -250,11 +250,10 @@ exports.getAllDbs = async () => {
|
|||
/**
|
||||
* Lots of different points in the system need to find the full list of apps, this will
|
||||
* enumerate the entire CouchDB cluster and get the list of databases (every app).
|
||||
* NOTE: this operation is fine in self hosting, but cannot be used when hosting many
|
||||
* different users/companies apps as there is no security around it - all apps are returned.
|
||||
* @return {Promise<object[]>} returns the app information document stored in each app database.
|
||||
*/
|
||||
exports.getAllApps = async (CouchDB, { dev, all, idsOnly } = {}) => {
|
||||
exports.getAllApps = async ({ dev, all, idsOnly } = {}) => {
|
||||
const CouchDB = getCouch()
|
||||
let tenantId = getTenantId()
|
||||
if (!env.MULTI_TENANCY && !tenantId) {
|
||||
tenantId = DEFAULT_TENANT_ID
|
||||
|
@ -310,8 +309,8 @@ exports.getAllApps = async (CouchDB, { dev, all, idsOnly } = {}) => {
|
|||
/**
|
||||
* Utility function for getAllApps but filters to production apps only.
|
||||
*/
|
||||
exports.getDeployedAppIDs = async CouchDB => {
|
||||
return (await exports.getAllApps(CouchDB, { idsOnly: true })).filter(
|
||||
exports.getDeployedAppIDs = async () => {
|
||||
return (await exports.getAllApps({ idsOnly: true })).filter(
|
||||
id => !exports.isDevAppID(id)
|
||||
)
|
||||
}
|
||||
|
@ -319,13 +318,14 @@ exports.getDeployedAppIDs = async CouchDB => {
|
|||
/**
|
||||
* Utility function for the inverse of above.
|
||||
*/
|
||||
exports.getDevAppIDs = async CouchDB => {
|
||||
return (await exports.getAllApps(CouchDB, { idsOnly: true })).filter(id =>
|
||||
exports.getDevAppIDs = async () => {
|
||||
return (await exports.getAllApps({ idsOnly: true })).filter(id =>
|
||||
exports.isDevAppID(id)
|
||||
)
|
||||
}
|
||||
|
||||
exports.dbExists = async (CouchDB, dbName) => {
|
||||
exports.dbExists = async dbName => {
|
||||
const CouchDB = getCouch()
|
||||
let exists = false
|
||||
try {
|
||||
const db = CouchDB(dbName, { skip_setup: true })
|
||||
|
|
|
@ -3,6 +3,7 @@ const {
|
|||
updateTenantId,
|
||||
isTenantIdSet,
|
||||
DEFAULT_TENANT_ID,
|
||||
updateAppId,
|
||||
} = require("../tenancy")
|
||||
const ContextFactory = require("../tenancy/FunctionContext")
|
||||
const { getTenantIDFromAppID } = require("../db/utils")
|
||||
|
@ -21,5 +22,6 @@ module.exports = () => {
|
|||
const appId = ctx.appId ? ctx.appId : ctx.user ? ctx.user.appId : null
|
||||
const tenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID
|
||||
updateTenantId(tenantId)
|
||||
updateAppId(appId)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const { getDB } = require("../db")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { BUILTIN_PERMISSION_IDS } = require("./permissions")
|
||||
const {
|
||||
|
@ -7,6 +6,7 @@ const {
|
|||
DocumentTypes,
|
||||
SEPARATOR,
|
||||
} = require("../db/utils")
|
||||
const { getAppDB } = require("../tenancy/context")
|
||||
|
||||
const BUILTIN_IDS = {
|
||||
ADMIN: "ADMIN",
|
||||
|
@ -111,11 +111,10 @@ exports.lowerBuiltinRoleID = (roleId1, roleId2) => {
|
|||
/**
|
||||
* Gets the role object, this is mainly useful for two purposes, to check if the level exists and
|
||||
* to check if the role inherits any others.
|
||||
* @param {string} appId The app in which to look for the role.
|
||||
* @param {string|null} roleId The level ID to lookup.
|
||||
* @returns {Promise<Role|object|null>} The role object, which may contain an "inherits" property.
|
||||
*/
|
||||
exports.getRole = async (appId, roleId) => {
|
||||
exports.getRole = async roleId => {
|
||||
if (!roleId) {
|
||||
return null
|
||||
}
|
||||
|
@ -128,7 +127,7 @@ exports.getRole = async (appId, roleId) => {
|
|||
)
|
||||
}
|
||||
try {
|
||||
const db = getDB(appId)
|
||||
const db = getAppDB()
|
||||
const dbRole = await db.get(exports.getDBRoleID(roleId))
|
||||
role = Object.assign(role, dbRole)
|
||||
// finalise the ID
|
||||
|
@ -145,11 +144,11 @@ exports.getRole = async (appId, roleId) => {
|
|||
/**
|
||||
* Simple function to get all the roles based on the top level user role ID.
|
||||
*/
|
||||
async function getAllUserRoles(appId, userRoleId) {
|
||||
async function getAllUserRoles(userRoleId) {
|
||||
if (!userRoleId) {
|
||||
return [BUILTIN_IDS.BASIC]
|
||||
}
|
||||
let currentRole = await exports.getRole(appId, userRoleId)
|
||||
let currentRole = await exports.getRole(userRoleId)
|
||||
let roles = currentRole ? [currentRole] : []
|
||||
let roleIds = [userRoleId]
|
||||
// get all the inherited roles
|
||||
|
@ -159,7 +158,7 @@ async function getAllUserRoles(appId, userRoleId) {
|
|||
roleIds.indexOf(currentRole.inherits) === -1
|
||||
) {
|
||||
roleIds.push(currentRole.inherits)
|
||||
currentRole = await exports.getRole(appId, currentRole.inherits)
|
||||
currentRole = await exports.getRole(currentRole.inherits)
|
||||
roles.push(currentRole)
|
||||
}
|
||||
return roles
|
||||
|
@ -168,29 +167,23 @@ async function getAllUserRoles(appId, userRoleId) {
|
|||
/**
|
||||
* Returns an ordered array of the user's inherited role IDs, this can be used
|
||||
* to determine if a user can access something that requires a specific role.
|
||||
* @param {string} appId The ID of the application from which roles should be obtained.
|
||||
* @param {string} userRoleId The user's role ID, this can be found in their access token.
|
||||
* @param {object} opts Various options, such as whether to only retrieve the IDs (default true).
|
||||
* @returns {Promise<string[]>} returns an ordered array of the roles, with the first being their
|
||||
* highest level of access and the last being the lowest level.
|
||||
*/
|
||||
exports.getUserRoleHierarchy = async (
|
||||
appId,
|
||||
userRoleId,
|
||||
opts = { idOnly: true }
|
||||
) => {
|
||||
exports.getUserRoleHierarchy = async (userRoleId, opts = { idOnly: true }) => {
|
||||
// special case, if they don't have a role then they are a public user
|
||||
const roles = await getAllUserRoles(appId, userRoleId)
|
||||
const roles = await getAllUserRoles(userRoleId)
|
||||
return opts.idOnly ? roles.map(role => role._id) : roles
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an app ID this will retrieve all of the roles that are currently within that app.
|
||||
* @param {string} appId The ID of the app to retrieve the roles from.
|
||||
* @return {Promise<object[]>} An array of the role objects that were found.
|
||||
*/
|
||||
exports.getAllRoles = async appId => {
|
||||
const db = getDB(appId)
|
||||
exports.getAllRoles = async () => {
|
||||
const db = getAppDB()
|
||||
const body = await db.allDocs(
|
||||
getRoleParams(null, {
|
||||
include_docs: true,
|
||||
|
@ -218,19 +211,17 @@ exports.getAllRoles = async appId => {
|
|||
}
|
||||
|
||||
/**
|
||||
* This retrieves the required role/
|
||||
* @param appId
|
||||
* This retrieves the required role
|
||||
* @param permLevel
|
||||
* @param resourceId
|
||||
* @param subResourceId
|
||||
* @return {Promise<{permissions}|Object>}
|
||||
*/
|
||||
exports.getRequiredResourceRole = async (
|
||||
appId,
|
||||
permLevel,
|
||||
{ resourceId, subResourceId }
|
||||
) => {
|
||||
const roles = await exports.getAllRoles(appId)
|
||||
const roles = await exports.getAllRoles()
|
||||
let main = [],
|
||||
sub = []
|
||||
for (let role of roles) {
|
||||
|
@ -251,8 +242,7 @@ exports.getRequiredResourceRole = async (
|
|||
}
|
||||
|
||||
class AccessController {
|
||||
constructor(appId) {
|
||||
this.appId = appId
|
||||
constructor() {
|
||||
this.userHierarchies = {}
|
||||
}
|
||||
|
||||
|
@ -270,7 +260,7 @@ class AccessController {
|
|||
}
|
||||
let roleIds = this.userHierarchies[userRoleId]
|
||||
if (!roleIds) {
|
||||
roleIds = await exports.getUserRoleHierarchy(this.appId, userRoleId)
|
||||
roleIds = await exports.getUserRoleHierarchy(userRoleId)
|
||||
this.userHierarchies[userRoleId] = roleIds
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ const { newid } = require("../hashing")
|
|||
const REQUEST_ID_KEY = "requestId"
|
||||
|
||||
class FunctionContext {
|
||||
static getMiddleware(updateCtxFn = null) {
|
||||
const namespace = this.createNamespace()
|
||||
static getMiddleware(updateCtxFn = null, contextName = "session") {
|
||||
const namespace = this.createNamespace(contextName)
|
||||
|
||||
return async function (ctx, next) {
|
||||
await new Promise(
|
||||
|
@ -24,14 +24,14 @@ class FunctionContext {
|
|||
}
|
||||
}
|
||||
|
||||
static run(callback) {
|
||||
const namespace = this.createNamespace()
|
||||
static run(callback, contextName = "session") {
|
||||
const namespace = this.createNamespace(contextName)
|
||||
|
||||
return namespace.runAndReturn(callback)
|
||||
}
|
||||
|
||||
static setOnContext(key, value) {
|
||||
const namespace = this.createNamespace()
|
||||
static setOnContext(key, value, contextName = "session") {
|
||||
const namespace = this.createNamespace(contextName)
|
||||
namespace.set(key, value)
|
||||
}
|
||||
|
||||
|
@ -55,16 +55,16 @@ class FunctionContext {
|
|||
}
|
||||
}
|
||||
|
||||
static destroyNamespace() {
|
||||
static destroyNamespace(name = "session") {
|
||||
if (this._namespace) {
|
||||
cls.destroyNamespace("session")
|
||||
cls.destroyNamespace(name)
|
||||
this._namespace = null
|
||||
}
|
||||
}
|
||||
|
||||
static createNamespace() {
|
||||
static createNamespace(name = "session") {
|
||||
if (!this._namespace) {
|
||||
this._namespace = cls.createNamespace("session")
|
||||
this._namespace = cls.createNamespace(name)
|
||||
}
|
||||
return this._namespace
|
||||
}
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
const env = require("../environment")
|
||||
const { Headers } = require("../../constants")
|
||||
const cls = require("./FunctionContext")
|
||||
const { getCouch } = require("../db")
|
||||
const { getDeployedAppID, getDevelopmentAppID } = require("../db/utils")
|
||||
const { isEqual } = require("lodash")
|
||||
|
||||
// some test cases call functions directly, need to
|
||||
// store an app ID to pretend there is a context
|
||||
let TEST_APP_ID = null
|
||||
|
||||
const ContextKeys = {
|
||||
TENANT_ID: "tenantId",
|
||||
APP_ID: "appId",
|
||||
// whatever the request app DB was
|
||||
CURRENT_DB: "currentDb",
|
||||
// get the prod app DB from the request
|
||||
PROD_DB: "prodDb",
|
||||
// get the dev app DB from the request
|
||||
DEV_DB: "devDb",
|
||||
DB_OPTS: "dbOpts",
|
||||
}
|
||||
|
||||
exports.DEFAULT_TENANT_ID = "default"
|
||||
|
||||
|
@ -12,13 +31,11 @@ exports.isMultiTenant = () => {
|
|||
return env.MULTI_TENANCY
|
||||
}
|
||||
|
||||
const TENANT_ID = "tenantId"
|
||||
|
||||
// used for automations, API endpoints should always be in context already
|
||||
exports.doInTenant = (tenantId, task) => {
|
||||
return cls.run(() => {
|
||||
// set the tenant id
|
||||
cls.setOnContext(TENANT_ID, tenantId)
|
||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
||||
|
||||
// invoke the task
|
||||
return task()
|
||||
|
@ -26,7 +43,19 @@ exports.doInTenant = (tenantId, task) => {
|
|||
}
|
||||
|
||||
exports.updateTenantId = tenantId => {
|
||||
cls.setOnContext(TENANT_ID, tenantId)
|
||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
||||
}
|
||||
|
||||
exports.updateAppId = appId => {
|
||||
try {
|
||||
cls.setOnContext(ContextKeys.APP_ID, appId)
|
||||
} catch (err) {
|
||||
if (env.isTest()) {
|
||||
TEST_APP_ID = appId
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.setTenantId = (
|
||||
|
@ -36,7 +65,7 @@ exports.setTenantId = (
|
|||
let tenantId
|
||||
// exit early if not multi-tenant
|
||||
if (!exports.isMultiTenant()) {
|
||||
cls.setOnContext(TENANT_ID, this.DEFAULT_TENANT_ID)
|
||||
cls.setOnContext(ContextKeys.TENANT_ID, this.DEFAULT_TENANT_ID)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -63,12 +92,12 @@ exports.setTenantId = (
|
|||
}
|
||||
// check tenant ID just incase no tenant was allowed
|
||||
if (tenantId) {
|
||||
cls.setOnContext(TENANT_ID, tenantId)
|
||||
cls.setOnContext(ContextKeys.TENANT_ID, tenantId)
|
||||
}
|
||||
}
|
||||
|
||||
exports.isTenantIdSet = () => {
|
||||
const tenantId = cls.getFromContext(TENANT_ID)
|
||||
const tenantId = cls.getFromContext(ContextKeys.TENANT_ID)
|
||||
return !!tenantId
|
||||
}
|
||||
|
||||
|
@ -76,9 +105,77 @@ exports.getTenantId = () => {
|
|||
if (!exports.isMultiTenant()) {
|
||||
return exports.DEFAULT_TENANT_ID
|
||||
}
|
||||
const tenantId = cls.getFromContext(TENANT_ID)
|
||||
const tenantId = cls.getFromContext(ContextKeys.TENANT_ID)
|
||||
if (!tenantId) {
|
||||
throw Error("Tenant id not found")
|
||||
}
|
||||
return tenantId
|
||||
}
|
||||
|
||||
exports.getAppId = () => {
|
||||
const foundId = cls.getFromContext(ContextKeys.APP_ID)
|
||||
if (!foundId && env.isTest() && TEST_APP_ID) {
|
||||
return TEST_APP_ID
|
||||
} else {
|
||||
return foundId
|
||||
}
|
||||
}
|
||||
|
||||
function getDB(key, opts) {
|
||||
const dbOptsKey = `${key}${ContextKeys.DB_OPTS}`
|
||||
let storedOpts = cls.getFromContext(dbOptsKey)
|
||||
let db = cls.getFromContext(key)
|
||||
if (db && isEqual(opts, storedOpts)) {
|
||||
return db
|
||||
}
|
||||
const appId = exports.getAppId()
|
||||
const CouchDB = getCouch()
|
||||
let toUseAppId
|
||||
switch (key) {
|
||||
case ContextKeys.CURRENT_DB:
|
||||
toUseAppId = appId
|
||||
break
|
||||
case ContextKeys.PROD_DB:
|
||||
toUseAppId = getDeployedAppID(appId)
|
||||
break
|
||||
case ContextKeys.DEV_DB:
|
||||
toUseAppId = getDevelopmentAppID(appId)
|
||||
break
|
||||
}
|
||||
db = new CouchDB(toUseAppId, opts)
|
||||
try {
|
||||
cls.setOnContext(key, db)
|
||||
if (opts) {
|
||||
cls.setOnContext(dbOptsKey, opts)
|
||||
}
|
||||
} catch (err) {
|
||||
if (!env.isTest()) {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the app database based on whatever the request
|
||||
* contained, dev or prod.
|
||||
*/
|
||||
exports.getAppDB = opts => {
|
||||
return getDB(ContextKeys.CURRENT_DB, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* This specifically gets the prod app ID, if the request
|
||||
* contained a development app ID, this will open the prod one.
|
||||
*/
|
||||
exports.getProdAppDB = opts => {
|
||||
return getDB(ContextKeys.PROD_DB, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
* This specifically gets the dev app ID, if the request
|
||||
* contained a prod app ID, this will open the dev one.
|
||||
*/
|
||||
exports.getDevAppDB = opts => {
|
||||
return getDB(ContextKeys.DEV_DB, opts)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../db")
|
||||
const env = require("../../environment")
|
||||
const packageJson = require("../../../package.json")
|
||||
const {
|
||||
|
@ -45,11 +44,13 @@ const { getTenantId, isMultiTenant } = require("@budibase/backend-core/tenancy")
|
|||
const { syncGlobalUsers } = require("./user")
|
||||
const { app: appCache } = require("@budibase/backend-core/cache")
|
||||
const { cleanupAutomations } = require("../../automations/utils")
|
||||
const context = require("@budibase/backend-core/context")
|
||||
|
||||
const URL_REGEX_SLASH = /\/|\\/g
|
||||
|
||||
// utility function, need to do away with this
|
||||
async function getLayouts(db) {
|
||||
async function getLayouts() {
|
||||
const db = context.getAppDB()
|
||||
return (
|
||||
await db.allDocs(
|
||||
getLayoutParams(null, {
|
||||
|
@ -59,7 +60,8 @@ async function getLayouts(db) {
|
|||
).rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
async function getScreens(db) {
|
||||
async function getScreens() {
|
||||
const db = context.getAppDB()
|
||||
return (
|
||||
await db.allDocs(
|
||||
getScreenParams(null, {
|
||||
|
@ -116,8 +118,9 @@ async function createInstance(template) {
|
|||
const tenantId = isMultiTenant() ? getTenantId() : null
|
||||
const baseAppId = generateAppID(tenantId)
|
||||
const appId = generateDevAppID(baseAppId)
|
||||
context.updateAppId(appId)
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = context.getAppDB()
|
||||
await db.put({
|
||||
_id: "_design/database",
|
||||
// view collation information, read before writing any complex views:
|
||||
|
@ -127,9 +130,9 @@ async function createInstance(template) {
|
|||
|
||||
// NOTE: indexes need to be created before any tables/templates
|
||||
// add view for linked rows
|
||||
await createLinkView(appId)
|
||||
await createRoutingView(appId)
|
||||
await createAllSearchIndex(appId)
|
||||
await createLinkView()
|
||||
await createRoutingView()
|
||||
await createAllSearchIndex()
|
||||
|
||||
// replicate the template data to the instance DB
|
||||
// this is currently very hard to test, downloading and importing template files
|
||||
|
@ -155,7 +158,7 @@ async function createInstance(template) {
|
|||
exports.fetch = async ctx => {
|
||||
const dev = ctx.query && ctx.query.status === AppStatus.DEV
|
||||
const all = ctx.query && ctx.query.status === AppStatus.ALL
|
||||
const apps = await getAllApps(CouchDB, { dev, all })
|
||||
const apps = await getAllApps({ dev, all })
|
||||
|
||||
// get the locks for all the dev apps
|
||||
if (dev || all) {
|
||||
|
@ -178,12 +181,11 @@ exports.fetch = async ctx => {
|
|||
}
|
||||
|
||||
exports.fetchAppDefinition = async ctx => {
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const layouts = await getLayouts(db)
|
||||
const layouts = await getLayouts()
|
||||
const userRoleId = getUserRoleId(ctx)
|
||||
const accessController = new AccessController(ctx.params.appId)
|
||||
const accessController = new AccessController()
|
||||
const screens = await accessController.checkScreensAccess(
|
||||
await getScreens(db),
|
||||
await getScreens(),
|
||||
userRoleId
|
||||
)
|
||||
ctx.body = {
|
||||
|
@ -194,15 +196,15 @@ exports.fetchAppDefinition = async ctx => {
|
|||
}
|
||||
|
||||
exports.fetchAppPackage = async ctx => {
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const db = context.getAppDB()
|
||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||
const layouts = await getLayouts(db)
|
||||
let screens = await getScreens(db)
|
||||
const layouts = await getLayouts()
|
||||
let screens = await getScreens()
|
||||
|
||||
// Only filter screens if the user is not a builder
|
||||
if (!(ctx.user.builder && ctx.user.builder.global)) {
|
||||
const userRoleId = getUserRoleId(ctx)
|
||||
const accessController = new AccessController(ctx.params.appId)
|
||||
const accessController = new AccessController()
|
||||
screens = await accessController.checkScreensAccess(screens, userRoleId)
|
||||
}
|
||||
|
||||
|
@ -215,7 +217,7 @@ exports.fetchAppPackage = async ctx => {
|
|||
}
|
||||
|
||||
exports.create = async ctx => {
|
||||
const apps = await getAllApps(CouchDB, { dev: true })
|
||||
const apps = await getAllApps({ dev: true })
|
||||
const name = ctx.request.body.name
|
||||
checkAppName(ctx, apps, name)
|
||||
const url = await getAppUrl(ctx)
|
||||
|
@ -233,7 +235,7 @@ exports.create = async ctx => {
|
|||
const instance = await createInstance(instanceConfig)
|
||||
const appId = instance._id
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = context.getAppDB()
|
||||
let _rev
|
||||
try {
|
||||
// if template there will be an existing doc
|
||||
|
@ -277,7 +279,7 @@ exports.create = async ctx => {
|
|||
}
|
||||
|
||||
exports.update = async ctx => {
|
||||
const apps = await getAllApps(CouchDB, { dev: true })
|
||||
const apps = await getAllApps({ dev: true })
|
||||
// validation
|
||||
const name = ctx.request.body.name
|
||||
checkAppName(ctx, apps, name, ctx.params.appId)
|
||||
|
@ -292,7 +294,7 @@ exports.update = async ctx => {
|
|||
|
||||
exports.updateClient = async ctx => {
|
||||
// Get current app version
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const db = context.getAppDB()
|
||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||
const currentVersion = application.version
|
||||
|
||||
|
@ -314,7 +316,7 @@ exports.updateClient = async ctx => {
|
|||
|
||||
exports.revertClient = async ctx => {
|
||||
// Check app can be reverted
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const db = context.getAppDB()
|
||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||
if (!application.revertableVersion) {
|
||||
ctx.throw(400, "There is no version to revert to")
|
||||
|
@ -336,7 +338,7 @@ exports.revertClient = async ctx => {
|
|||
}
|
||||
|
||||
exports.delete = async ctx => {
|
||||
const db = new CouchDB(ctx.params.appId)
|
||||
const db = context.getAppDB()
|
||||
|
||||
const result = await db.destroy()
|
||||
/* istanbul ignore next */
|
||||
|
@ -364,7 +366,8 @@ exports.sync = async (ctx, next) => {
|
|||
const prodAppId = getDeployedAppID(appId)
|
||||
|
||||
try {
|
||||
const prodDb = new CouchDB(prodAppId, { skip_setup: true })
|
||||
// specific case, want to make sure setup is skipped
|
||||
const prodDb = context.getProdAppDB({ skip_setup: true })
|
||||
const info = await prodDb.info()
|
||||
if (info.error) throw info.error
|
||||
} catch (err) {
|
||||
|
@ -392,7 +395,7 @@ exports.sync = async (ctx, next) => {
|
|||
}
|
||||
|
||||
// sync the users
|
||||
await syncGlobalUsers(appId)
|
||||
await syncGlobalUsers()
|
||||
|
||||
if (error) {
|
||||
ctx.throw(400, error)
|
||||
|
@ -404,7 +407,7 @@ exports.sync = async (ctx, next) => {
|
|||
}
|
||||
|
||||
const updateAppPackage = async (appPackage, appId) => {
|
||||
const db = new CouchDB(appId)
|
||||
const db = context.getAppDB()
|
||||
const application = await db.get(DocumentTypes.APP_METADATA)
|
||||
|
||||
const newAppPackage = { ...application, ...appPackage }
|
||||
|
@ -423,7 +426,7 @@ const updateAppPackage = async (appPackage, appId) => {
|
|||
}
|
||||
|
||||
const createEmptyAppPackage = async (ctx, app) => {
|
||||
const db = new CouchDB(app.appId)
|
||||
const db = context.getAppDB()
|
||||
|
||||
let screensAndLayouts = []
|
||||
for (let layout of BASE_LAYOUTS) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
const env = require("../../environment")
|
||||
const { getAllApps } = require("@budibase/backend-core/db")
|
||||
const CouchDB = require("../../db")
|
||||
const {
|
||||
exportDB,
|
||||
sendTempFile,
|
||||
|
@ -30,7 +29,7 @@ exports.exportApps = async ctx => {
|
|||
if (env.SELF_HOSTED || !env.MULTI_TENANCY) {
|
||||
ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.")
|
||||
}
|
||||
const apps = await getAllApps(CouchDB, { all: true })
|
||||
const apps = await getAllApps({ all: true })
|
||||
const globalDBString = await exportDB(getGlobalDBName(), {
|
||||
filter: doc => !doc._id.startsWith(DocumentTypes.USER),
|
||||
})
|
||||
|
@ -63,7 +62,7 @@ async function hasBeenImported() {
|
|||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
||||
return true
|
||||
}
|
||||
const apps = await getAllApps(CouchDB, { all: true })
|
||||
const apps = await getAllApps({ all: true })
|
||||
return apps.length !== 0
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
const CouchDB = require("../../db")
|
||||
const { DocumentTypes } = require("../../db/utils")
|
||||
const { getComponentLibraryManifest } = require("../../utilities/fileSystem")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.fetchAppComponentDefinitions = async function (ctx) {
|
||||
const appId = ctx.params.appId || ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const app = await db.get(DocumentTypes.APP_METADATA)
|
||||
|
||||
let componentManifests = await Promise.all(
|
||||
app.componentLibraries.map(async library => {
|
||||
let manifest = await getComponentLibraryManifest(appId, library)
|
||||
let manifest = await getComponentLibraryManifest(library)
|
||||
|
||||
return {
|
||||
manifest,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../db")
|
||||
const {
|
||||
generateDatasourceID,
|
||||
getDatasourceParams,
|
||||
|
@ -11,12 +10,11 @@ const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
|
|||
const { integrations } = require("../../integrations")
|
||||
const { getDatasourceAndQuery } = require("./row/utils")
|
||||
const { invalidateDynamicVariables } = require("../../threads/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
const database = new CouchDB(ctx.appId)
|
||||
|
||||
// Get internal tables
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const internalTables = await db.allDocs(
|
||||
getTableParams(null, {
|
||||
include_docs: true,
|
||||
|
@ -31,7 +29,7 @@ exports.fetch = async function (ctx) {
|
|||
|
||||
// Get external datasources
|
||||
const datasources = (
|
||||
await database.allDocs(
|
||||
await db.allDocs(
|
||||
getDatasourceParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
|
@ -49,7 +47,7 @@ exports.fetch = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.buildSchemaFromDb = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
|
||||
const { tables, error } = await buildSchemaHelper(datasource)
|
||||
|
@ -98,7 +96,7 @@ const invalidateVariables = async (existingDatasource, updatedDatasource) => {
|
|||
}
|
||||
|
||||
exports.update = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const datasourceId = ctx.params.datasourceId
|
||||
let datasource = await db.get(datasourceId)
|
||||
const auth = datasource.config.auth
|
||||
|
@ -126,7 +124,7 @@ exports.update = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const plus = ctx.request.body.datasource.plus
|
||||
const fetchSchema = ctx.request.body.fetchSchema
|
||||
|
||||
|
@ -162,7 +160,7 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
|
||||
// Delete all queries for the datasource
|
||||
const queries = await db.allDocs(
|
||||
|
@ -184,7 +182,7 @@ exports.destroy = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
const database = new CouchDB(ctx.appId)
|
||||
const database = getAppDB()
|
||||
ctx.body = await database.get(ctx.params.datasourceId)
|
||||
}
|
||||
|
||||
|
@ -192,7 +190,7 @@ exports.find = async function (ctx) {
|
|||
exports.query = async function (ctx) {
|
||||
const queryJson = ctx.request.body
|
||||
try {
|
||||
ctx.body = await getDatasourceAndQuery(ctx.appId, queryJson)
|
||||
ctx.body = await getDatasourceAndQuery(queryJson)
|
||||
} catch (err) {
|
||||
ctx.throw(400, err)
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ const {
|
|||
EMPTY_LAYOUT,
|
||||
BASE_LAYOUT_PROP_IDS,
|
||||
} = require("../../constants/layouts")
|
||||
const CouchDB = require("../../db")
|
||||
const { generateLayoutID, getScreenParams } = require("../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
let layout = ctx.request.body
|
||||
|
||||
if (!layout.props) {
|
||||
|
@ -26,7 +26,7 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const layoutId = ctx.params.layoutId,
|
||||
layoutRev = ctx.params.layoutRev
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ const {
|
|||
getBuiltinRoles,
|
||||
} = require("@budibase/backend-core/roles")
|
||||
const { getRoleParams } = require("../../db/utils")
|
||||
const CouchDB = require("../../db")
|
||||
const {
|
||||
CURRENTLY_SUPPORTED_LEVELS,
|
||||
getBasePermissions,
|
||||
} = require("../../utilities/security")
|
||||
const { removeFromArray } = require("../../utilities")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
const PermissionUpdateType = {
|
||||
REMOVE: "remove",
|
||||
|
@ -35,7 +35,7 @@ async function updatePermissionOnRole(
|
|||
{ roleId, resourceId, level },
|
||||
updateType
|
||||
) {
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const remove = updateType === PermissionUpdateType.REMOVE
|
||||
const isABuiltin = isBuiltin(roleId)
|
||||
const dbRoleId = getDBRoleID(roleId)
|
||||
|
@ -106,7 +106,7 @@ exports.fetchLevels = function (ctx) {
|
|||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const roles = await getAllDBRoles(db)
|
||||
let permissions = {}
|
||||
// create an object with structure role ID -> resource ID -> level
|
||||
|
@ -133,7 +133,7 @@ exports.fetch = async function (ctx) {
|
|||
|
||||
exports.getResourcePerms = async function (ctx) {
|
||||
const resourceId = ctx.params.resourceId
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const body = await db.allDocs(
|
||||
getRoleParams(null, {
|
||||
include_docs: true,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../db")
|
||||
const {
|
||||
Role,
|
||||
getRole,
|
||||
|
@ -10,6 +9,7 @@ const {
|
|||
getUserMetadataParams,
|
||||
InternalTables,
|
||||
} = require("../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
const UpdateRolesOptions = {
|
||||
CREATED: "created",
|
||||
|
@ -40,15 +40,15 @@ async function updateRolesOnUserTable(db, roleId, updateOption) {
|
|||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
ctx.body = await getAllRoles(ctx.appId)
|
||||
ctx.body = await getAllRoles()
|
||||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
ctx.body = await getRole(ctx.appId, ctx.params.roleId)
|
||||
ctx.body = await getRole(ctx.params.roleId)
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
let { _id, name, inherits, permissionId } = ctx.request.body
|
||||
if (!_id) {
|
||||
_id = generateRoleID()
|
||||
|
@ -69,7 +69,7 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const roleId = ctx.params.roleId
|
||||
if (isBuiltin(roleId)) {
|
||||
ctx.throw(400, "Cannot delete builtin role.")
|
||||
|
|
|
@ -63,7 +63,7 @@ exports.fetch = async ctx => {
|
|||
exports.clientFetch = async ctx => {
|
||||
const routing = await getRoutingStructure(ctx.appId)
|
||||
let roleId = ctx.user.role._id
|
||||
const roleIds = await getUserRoleHierarchy(ctx.appId, roleId)
|
||||
const roleIds = await getUserRoleHierarchy(roleId)
|
||||
for (let topLevel of Object.values(routing.routes)) {
|
||||
for (let subpathKey of Object.keys(topLevel.subpaths)) {
|
||||
let found = false
|
||||
|
|
|
@ -19,6 +19,19 @@ import {
|
|||
isRowId,
|
||||
convertRowId,
|
||||
} from "../../../integrations/utils"
|
||||
import { getDatasourceAndQuery } from "./utils"
|
||||
import {
|
||||
DataSourceOperation,
|
||||
FieldTypes,
|
||||
RelationshipTypes,
|
||||
} from "../../../constants"
|
||||
import { breakExternalTableId, isSQL } from "../../../integrations/utils"
|
||||
import { processObjectSync } from "@budibase/string-templates"
|
||||
// @ts-ignore
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { processFormulas } from "../../../utilities/rowProcessor/utils"
|
||||
// @ts-ignore
|
||||
import { getAppDB } from "@budibase/backend-core/context"
|
||||
|
||||
interface ManyRelationship {
|
||||
tableId?: string
|
||||
|
@ -38,18 +51,6 @@ interface RunConfig {
|
|||
}
|
||||
|
||||
module External {
|
||||
const { getDatasourceAndQuery } = require("./utils")
|
||||
const {
|
||||
DataSourceOperation,
|
||||
FieldTypes,
|
||||
RelationshipTypes,
|
||||
} = require("../../../constants")
|
||||
const { breakExternalTableId, isSQL } = require("../../../integrations/utils")
|
||||
const { processObjectSync } = require("@budibase/string-templates")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const CouchDB = require("../../../db")
|
||||
const { processFormulas } = require("../../../utilities/rowProcessor/utils")
|
||||
|
||||
function buildFilters(
|
||||
id: string | undefined,
|
||||
filters: SearchFilters,
|
||||
|
@ -210,19 +211,16 @@ module External {
|
|||
}
|
||||
|
||||
class ExternalRequest {
|
||||
private readonly appId: string
|
||||
private operation: Operation
|
||||
private tableId: string
|
||||
private datasource: Datasource
|
||||
private tables: { [key: string]: Table } = {}
|
||||
|
||||
constructor(
|
||||
appId: string,
|
||||
operation: Operation,
|
||||
tableId: string,
|
||||
datasource: Datasource
|
||||
) {
|
||||
this.appId = appId
|
||||
this.operation = operation
|
||||
this.tableId = tableId
|
||||
this.datasource = datasource
|
||||
|
@ -231,12 +229,14 @@ module External {
|
|||
}
|
||||
}
|
||||
|
||||
getTable(tableId: string | undefined): Table {
|
||||
getTable(tableId: string | undefined): Table | undefined {
|
||||
if (!tableId) {
|
||||
throw "Table ID is unknown, cannot find table"
|
||||
}
|
||||
const { tableName } = breakExternalTableId(tableId)
|
||||
return this.tables[tableName]
|
||||
if (tableName) {
|
||||
return this.tables[tableName]
|
||||
}
|
||||
}
|
||||
|
||||
inputProcessing(row: Row | undefined, table: Table) {
|
||||
|
@ -272,9 +272,9 @@ module External {
|
|||
newRow[key] = row[key]
|
||||
continue
|
||||
}
|
||||
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||
const { tableName: linkTableName } = breakExternalTableId(field?.tableId)
|
||||
// table has to exist for many to many
|
||||
if (!this.tables[linkTableName]) {
|
||||
if (!linkTableName || !this.tables[linkTableName]) {
|
||||
continue
|
||||
}
|
||||
const linkTable = this.tables[linkTableName]
|
||||
|
@ -422,7 +422,7 @@ module External {
|
|||
}
|
||||
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||
// no table to link to, this is not a valid relationships
|
||||
if (!this.tables[linkTableName]) {
|
||||
if (!linkTableName || !this.tables[linkTableName]) {
|
||||
continue
|
||||
}
|
||||
const linkTable = this.tables[linkTableName]
|
||||
|
@ -460,6 +460,9 @@ module External {
|
|||
async lookupRelations(tableId: string, row: Row) {
|
||||
const related: { [key: string]: any } = {}
|
||||
const { tableName } = breakExternalTableId(tableId)
|
||||
if (!tableName) {
|
||||
return related
|
||||
}
|
||||
const table = this.tables[tableName]
|
||||
// @ts-ignore
|
||||
const primaryKey = table.primary[0]
|
||||
|
@ -484,7 +487,7 @@ module External {
|
|||
if (!lookupField || !row[lookupField]) {
|
||||
continue
|
||||
}
|
||||
const response = await getDatasourceAndQuery(this.appId, {
|
||||
const response = await getDatasourceAndQuery({
|
||||
endpoint: getEndpoint(tableId, DataSourceOperation.READ),
|
||||
filters: {
|
||||
equal: {
|
||||
|
@ -515,28 +518,30 @@ module External {
|
|||
row: Row,
|
||||
relationships: ManyRelationship[]
|
||||
) {
|
||||
const { appId } = this
|
||||
// if we're creating (in a through table) need to wipe the existing ones first
|
||||
const promises = []
|
||||
const related = await this.lookupRelations(mainTableId, row)
|
||||
for (let relationship of relationships) {
|
||||
const { key, tableId, isUpdate, id, ...rest } = relationship
|
||||
const body = processObjectSync(rest, row)
|
||||
const body: { [key: string]: any } = processObjectSync(rest, row, {})
|
||||
const linkTable = this.getTable(tableId)
|
||||
// @ts-ignore
|
||||
const linkPrimary = linkTable.primary[0]
|
||||
const linkPrimary = linkTable?.primary[0]
|
||||
if (!linkTable || !linkPrimary) {
|
||||
return
|
||||
}
|
||||
const rows = related[key].rows || []
|
||||
const found = rows.find(
|
||||
(row: { [key: string]: any }) =>
|
||||
row[linkPrimary] === relationship.id ||
|
||||
row[linkPrimary] === body[linkPrimary]
|
||||
row[linkPrimary] === body?.[linkPrimary]
|
||||
)
|
||||
const operation = isUpdate
|
||||
? DataSourceOperation.UPDATE
|
||||
: DataSourceOperation.CREATE
|
||||
if (!found) {
|
||||
promises.push(
|
||||
getDatasourceAndQuery(appId, {
|
||||
getDatasourceAndQuery({
|
||||
endpoint: getEndpoint(tableId, operation),
|
||||
// if we're doing many relationships then we're writing, only one response
|
||||
body,
|
||||
|
@ -552,9 +557,9 @@ module External {
|
|||
for (let [colName, { isMany, rows, tableId }] of Object.entries(
|
||||
related
|
||||
)) {
|
||||
const table: Table = this.getTable(tableId)
|
||||
const table: Table | undefined = this.getTable(tableId)
|
||||
// if its not the foreign key skip it, nothing to do
|
||||
if (table.primary && table.primary.indexOf(colName) !== -1) {
|
||||
if (!table || (table.primary && table.primary.indexOf(colName) !== -1)) {
|
||||
continue
|
||||
}
|
||||
for (let row of rows) {
|
||||
|
@ -566,7 +571,7 @@ module External {
|
|||
: DataSourceOperation.UPDATE
|
||||
const body = isMany ? null : { [colName]: null }
|
||||
promises.push(
|
||||
getDatasourceAndQuery(this.appId, {
|
||||
getDatasourceAndQuery({
|
||||
endpoint: getEndpoint(tableId, op),
|
||||
body,
|
||||
filters,
|
||||
|
@ -605,20 +610,25 @@ module External {
|
|||
continue
|
||||
}
|
||||
const { tableName: linkTableName } = breakExternalTableId(field.tableId)
|
||||
const linkTable = this.tables[linkTableName]
|
||||
if (linkTable) {
|
||||
const linkedFields = extractRealFields(linkTable, fields)
|
||||
fields = fields.concat(linkedFields)
|
||||
if (linkTableName) {
|
||||
const linkTable = this.tables[linkTableName]
|
||||
if (linkTable) {
|
||||
const linkedFields = extractRealFields(linkTable, fields)
|
||||
fields = fields.concat(linkedFields)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
async run(config: RunConfig) {
|
||||
const { appId, operation, tableId } = this
|
||||
const { operation, tableId } = this
|
||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
if (!tableName) {
|
||||
throw "Unable to run without a table name"
|
||||
}
|
||||
if (!this.datasource) {
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
this.datasource = await db.get(datasourceId)
|
||||
if (!this.datasource || !this.datasource.entities) {
|
||||
throw "No tables found, fetch tables before query."
|
||||
|
@ -670,7 +680,7 @@ module External {
|
|||
},
|
||||
}
|
||||
// can't really use response right now
|
||||
const response = await getDatasourceAndQuery(appId, json)
|
||||
const response = await getDatasourceAndQuery(json)
|
||||
// handle many to many relationships now if we know the ID (could be auto increment)
|
||||
if (
|
||||
operation !== DataSourceOperation.READ &&
|
||||
|
|
|
@ -11,7 +11,7 @@ const {
|
|||
const ExternalRequest = require("./ExternalRequest")
|
||||
const CouchDB = require("../../../db")
|
||||
|
||||
async function handleRequest(appId, operation, tableId, opts = {}) {
|
||||
async function handleRequest(operation, tableId, opts = {}) {
|
||||
// make sure the filters are cleaned up, no empty strings for equals, fuzzy or string
|
||||
if (opts && opts.filters) {
|
||||
for (let filterField of NoEmptyFilterStrings) {
|
||||
|
@ -25,9 +25,7 @@ async function handleRequest(appId, operation, tableId, opts = {}) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return new ExternalRequest(appId, operation, tableId, opts.datasource).run(
|
||||
opts
|
||||
)
|
||||
return new ExternalRequest(operation, tableId, opts.datasource).run(opts)
|
||||
}
|
||||
|
||||
exports.handleRequest = handleRequest
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const linkRows = require("../../../db/linkedRows")
|
||||
const {
|
||||
getRowParams,
|
||||
|
@ -27,6 +26,7 @@ const {
|
|||
getFromMemoryDoc,
|
||||
} = require("../view/utils")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
const CALCULATION_TYPES = {
|
||||
SUM: "sum",
|
||||
|
@ -106,8 +106,7 @@ async function getView(db, viewName) {
|
|||
}
|
||||
|
||||
exports.patch = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const inputs = ctx.request.body
|
||||
const tableId = inputs.tableId
|
||||
const isUserTable = tableId === InternalTables.USER_METADATA
|
||||
|
@ -146,14 +145,13 @@ exports.patch = async ctx => {
|
|||
|
||||
// returned row is cleaned and prepared for writing to DB
|
||||
row = await linkRows.updateLinks({
|
||||
appId,
|
||||
eventType: linkRows.EventType.ROW_UPDATE,
|
||||
row,
|
||||
tableId: row.tableId,
|
||||
table,
|
||||
})
|
||||
// check if any attachments removed
|
||||
await cleanupAttachments(appId, table, { oldRow, row })
|
||||
await cleanupAttachments(table, { oldRow, row })
|
||||
|
||||
if (isUserTable) {
|
||||
// the row has been updated, need to put it into the ctx
|
||||
|
@ -166,8 +164,7 @@ exports.patch = async ctx => {
|
|||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
let inputs = ctx.request.body
|
||||
inputs.tableId = ctx.params.tableId
|
||||
|
||||
|
@ -189,7 +186,6 @@ exports.save = async function (ctx) {
|
|||
|
||||
// make sure link rows are up to date
|
||||
row = await linkRows.updateLinks({
|
||||
appId,
|
||||
eventType: linkRows.EventType.ROW_SAVE,
|
||||
row,
|
||||
tableId: row.tableId,
|
||||
|
@ -200,7 +196,6 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.fetchView = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const viewName = ctx.params.viewName
|
||||
|
||||
// if this is a table view being looked for just transfer to that
|
||||
|
@ -209,7 +204,7 @@ exports.fetchView = async ctx => {
|
|||
return exports.fetch(ctx)
|
||||
}
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const { calculation, group, field } = ctx.query
|
||||
const viewInfo = await getView(db, viewName)
|
||||
let response
|
||||
|
@ -263,8 +258,7 @@ exports.fetchView = async ctx => {
|
|||
}
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
|
||||
const tableId = ctx.params.tableId
|
||||
let table = await db.get(tableId)
|
||||
|
@ -273,17 +267,15 @@ exports.fetch = async ctx => {
|
|||
}
|
||||
|
||||
exports.find = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const table = await db.get(ctx.params.tableId)
|
||||
let row = await findRow(ctx, db, ctx.params.tableId, ctx.params.rowId)
|
||||
let row = await findRow(ctx, ctx.params.tableId, ctx.params.rowId)
|
||||
row = await outputProcessing(ctx, table, row)
|
||||
return row
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const { _id, _rev } = ctx.request.body
|
||||
let row = await db.get(_id)
|
||||
|
||||
|
@ -295,13 +287,12 @@ exports.destroy = async function (ctx) {
|
|||
row = await outputProcessing(ctx, table, row, { squash: false })
|
||||
// now remove the relationships
|
||||
await linkRows.updateLinks({
|
||||
appId,
|
||||
eventType: linkRows.EventType.ROW_DELETE,
|
||||
row,
|
||||
tableId: row.tableId,
|
||||
})
|
||||
// remove any attachments that were on the row from object storage
|
||||
await cleanupAttachments(appId, table, { row })
|
||||
await cleanupAttachments(table, { row })
|
||||
|
||||
let response
|
||||
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||
|
@ -317,8 +308,7 @@ exports.destroy = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.bulkDestroy = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const tableId = ctx.params.tableId
|
||||
const table = await db.get(tableId)
|
||||
let { rows } = ctx.request.body
|
||||
|
@ -330,7 +320,6 @@ exports.bulkDestroy = async ctx => {
|
|||
// remove the relationships first
|
||||
let updates = rows.map(row =>
|
||||
linkRows.updateLinks({
|
||||
appId,
|
||||
eventType: linkRows.EventType.ROW_DELETE,
|
||||
row,
|
||||
tableId: row.tableId,
|
||||
|
@ -349,7 +338,7 @@ exports.bulkDestroy = async ctx => {
|
|||
await db.bulkDocs(rows.map(row => ({ ...row, _deleted: true })))
|
||||
}
|
||||
// remove any attachments that were on the rows from object storage
|
||||
await cleanupAttachments(appId, table, { rows })
|
||||
await cleanupAttachments(table, { rows })
|
||||
await Promise.all(updates)
|
||||
return { response: { ok: true }, rows }
|
||||
}
|
||||
|
@ -360,25 +349,24 @@ exports.search = async ctx => {
|
|||
return { rows: await exports.fetch(ctx) }
|
||||
}
|
||||
|
||||
const appId = ctx.appId
|
||||
const { tableId } = ctx.params
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const { paginate, query, ...params } = ctx.request.body
|
||||
params.version = ctx.version
|
||||
params.tableId = tableId
|
||||
|
||||
let response
|
||||
if (paginate) {
|
||||
response = await paginatedSearch(appId, query, params)
|
||||
response = await paginatedSearch(query, params)
|
||||
} else {
|
||||
response = await fullSearch(appId, query, params)
|
||||
response = await fullSearch(query, params)
|
||||
}
|
||||
|
||||
// Enrich search results with relationships
|
||||
if (response.rows && response.rows.length) {
|
||||
// enrich with global users if from users table
|
||||
if (tableId === InternalTables.USER_METADATA) {
|
||||
response.rows = await getGlobalUsersFromMetadata(appId, response.rows)
|
||||
response.rows = await getGlobalUsersFromMetadata(response.rows)
|
||||
}
|
||||
const table = await db.get(tableId)
|
||||
response.rows = await outputProcessing(ctx, table, response.rows)
|
||||
|
@ -389,25 +377,22 @@ exports.search = async ctx => {
|
|||
|
||||
exports.validate = async ctx => {
|
||||
return validate({
|
||||
appId: ctx.appId,
|
||||
tableId: ctx.params.tableId,
|
||||
row: ctx.request.body,
|
||||
})
|
||||
}
|
||||
|
||||
exports.fetchEnrichedRow = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const tableId = ctx.params.tableId
|
||||
const rowId = ctx.params.rowId
|
||||
// need table to work out where links go in row
|
||||
let [table, row] = await Promise.all([
|
||||
db.get(tableId),
|
||||
findRow(ctx, db, tableId, rowId),
|
||||
findRow(ctx, tableId, rowId),
|
||||
])
|
||||
// get the link docs
|
||||
const linkVals = await linkRows.getLinkDocuments({
|
||||
appId,
|
||||
tableId,
|
||||
rowId,
|
||||
})
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
const { SearchIndexes } = require("../../../db/utils")
|
||||
const fetch = require("node-fetch")
|
||||
const { getCouchUrl } = require("@budibase/backend-core/db")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
|
||||
/**
|
||||
* Class to build lucene query URLs.
|
||||
* Optionally takes a base lucene query object.
|
||||
*/
|
||||
class QueryBuilder {
|
||||
constructor(appId, base) {
|
||||
this.appId = appId
|
||||
constructor(base) {
|
||||
this.query = {
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
|
@ -233,7 +233,8 @@ class QueryBuilder {
|
|||
}
|
||||
|
||||
async run() {
|
||||
const url = `${getCouchUrl()}/${this.appId}/_design/database/_search/${
|
||||
const appId = getAppId()
|
||||
const url = `${getCouchUrl()}/${appId}/_design/database/_search/${
|
||||
SearchIndexes.ROWS
|
||||
}`
|
||||
const body = this.buildSearchBody()
|
||||
|
@ -270,7 +271,6 @@ const runQuery = async (url, body) => {
|
|||
* Gets round the fixed limit of 200 results from a query by fetching as many
|
||||
* pages as required and concatenating the results. This recursively operates
|
||||
* until enough results have been found.
|
||||
* @param appId {string} The app ID to search
|
||||
* @param query {object} The JSON query structure
|
||||
* @param params {object} The search params including:
|
||||
* tableId {string} The table ID to search
|
||||
|
@ -283,7 +283,7 @@ const runQuery = async (url, body) => {
|
|||
* rows {array|null} Current results in the recursive search
|
||||
* @returns {Promise<*[]|*>}
|
||||
*/
|
||||
const recursiveSearch = async (appId, query, params) => {
|
||||
const recursiveSearch = async (query, params) => {
|
||||
const bookmark = params.bookmark
|
||||
const rows = params.rows || []
|
||||
if (rows.length >= params.limit) {
|
||||
|
@ -293,7 +293,7 @@ const recursiveSearch = async (appId, query, params) => {
|
|||
if (rows.length > params.limit - 200) {
|
||||
pageSize = params.limit - rows.length
|
||||
}
|
||||
const page = await new QueryBuilder(appId, query)
|
||||
const page = await new QueryBuilder(query)
|
||||
.setVersion(params.version)
|
||||
.setTable(params.tableId)
|
||||
.setBookmark(bookmark)
|
||||
|
@ -313,14 +313,13 @@ const recursiveSearch = async (appId, query, params) => {
|
|||
bookmark: page.bookmark,
|
||||
rows: [...rows, ...page.rows],
|
||||
}
|
||||
return await recursiveSearch(appId, query, newParams)
|
||||
return await recursiveSearch(query, newParams)
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a paginated search. A bookmark will be returned to allow the next
|
||||
* page to be fetched. There is a max limit off 200 results per page in a
|
||||
* paginated search.
|
||||
* @param appId {string} The app ID to search
|
||||
* @param query {object} The JSON query structure
|
||||
* @param params {object} The search params including:
|
||||
* tableId {string} The table ID to search
|
||||
|
@ -332,13 +331,13 @@ const recursiveSearch = async (appId, query, params) => {
|
|||
* bookmark {string} The bookmark to resume from
|
||||
* @returns {Promise<{hasNextPage: boolean, rows: *[]}>}
|
||||
*/
|
||||
exports.paginatedSearch = async (appId, query, params) => {
|
||||
exports.paginatedSearch = async (query, params) => {
|
||||
let limit = params.limit
|
||||
if (limit == null || isNaN(limit) || limit < 0) {
|
||||
limit = 50
|
||||
}
|
||||
limit = Math.min(limit, 200)
|
||||
const search = new QueryBuilder(appId, query)
|
||||
const search = new QueryBuilder(query)
|
||||
.setVersion(params.version)
|
||||
.setTable(params.tableId)
|
||||
.setSort(params.sort)
|
||||
|
@ -367,7 +366,6 @@ exports.paginatedSearch = async (appId, query, params) => {
|
|||
* desired amount of results. There is a limit of 1000 results to avoid
|
||||
* heavy performance hits, and to avoid client components breaking from
|
||||
* handling too much data.
|
||||
* @param appId {string} The app ID to search
|
||||
* @param query {object} The JSON query structure
|
||||
* @param params {object} The search params including:
|
||||
* tableId {string} The table ID to search
|
||||
|
@ -378,12 +376,12 @@ exports.paginatedSearch = async (appId, query, params) => {
|
|||
* limit {number} The desired number of results
|
||||
* @returns {Promise<{rows: *}>}
|
||||
*/
|
||||
exports.fullSearch = async (appId, query, params) => {
|
||||
exports.fullSearch = async (query, params) => {
|
||||
let limit = params.limit
|
||||
if (limit == null || isNaN(limit) || limit < 0) {
|
||||
limit = 1000
|
||||
}
|
||||
params.limit = Math.min(limit, 1000)
|
||||
const rows = await recursiveSearch(appId, query, params)
|
||||
const rows = await recursiveSearch(query, params)
|
||||
return { rows }
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
const validateJs = require("validate.js")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const CouchDB = require("../../../db")
|
||||
const { InternalTables } = require("../../../db/utils")
|
||||
const userController = require("../user")
|
||||
const { FieldTypes } = require("../../../constants")
|
||||
const { processStringSync } = require("@budibase/string-templates")
|
||||
const { makeExternalQuery } = require("../../../integrations/base/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
validateJs.extend(validateJs.validators.datetime, {
|
||||
parse: function (value) {
|
||||
|
@ -17,14 +17,15 @@ validateJs.extend(validateJs.validators.datetime, {
|
|||
},
|
||||
})
|
||||
|
||||
exports.getDatasourceAndQuery = async (appId, json) => {
|
||||
exports.getDatasourceAndQuery = async json => {
|
||||
const datasourceId = json.endpoint.datasourceId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
return makeExternalQuery(datasource, json)
|
||||
}
|
||||
|
||||
exports.findRow = async (ctx, db, tableId, rowId) => {
|
||||
exports.findRow = async (ctx, tableId, rowId) => {
|
||||
const db = getAppDB()
|
||||
let row
|
||||
// TODO remove special user case in future
|
||||
if (tableId === InternalTables.USER_METADATA) {
|
||||
|
@ -42,9 +43,9 @@ exports.findRow = async (ctx, db, tableId, rowId) => {
|
|||
return row
|
||||
}
|
||||
|
||||
exports.validate = async ({ appId, tableId, row, table }) => {
|
||||
exports.validate = async ({ tableId, row, table }) => {
|
||||
if (!table) {
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
table = await db.get(tableId)
|
||||
}
|
||||
const errors = {}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
const CouchDB = require("../../db")
|
||||
const { getScreenParams, generateScreenID } = require("../../db/utils")
|
||||
const { AccessController } = require("@budibase/backend-core/roles")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
|
||||
const screens = (
|
||||
await db.allDocs(
|
||||
|
@ -14,15 +13,14 @@ exports.fetch = async ctx => {
|
|||
)
|
||||
).rows.map(element => element.doc)
|
||||
|
||||
ctx.body = await new AccessController(appId).checkScreensAccess(
|
||||
ctx.body = await new AccessController().checkScreensAccess(
|
||||
screens,
|
||||
ctx.user.role._id
|
||||
)
|
||||
}
|
||||
|
||||
exports.save = async ctx => {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
let screen = ctx.request.body
|
||||
|
||||
if (!screen._id) {
|
||||
|
@ -39,7 +37,7 @@ exports.save = async ctx => {
|
|||
}
|
||||
|
||||
exports.destroy = async ctx => {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
await db.remove(ctx.params.screenId, ctx.params.screenRev)
|
||||
ctx.body = {
|
||||
message: "Screen deleted successfully",
|
||||
|
|
|
@ -6,7 +6,6 @@ const uuid = require("uuid")
|
|||
const { ObjectStoreBuckets } = require("../../../constants")
|
||||
const { processString } = require("@budibase/string-templates")
|
||||
const { getAllApps } = require("@budibase/backend-core/db")
|
||||
const CouchDB = require("../../../db")
|
||||
const {
|
||||
loadHandlebarsFile,
|
||||
NODE_MODULES_PATH,
|
||||
|
@ -17,6 +16,7 @@ const { clientLibraryPath } = require("../../../utilities")
|
|||
const { upload } = require("../../../utilities/fileSystem")
|
||||
const { attachmentsRelativeURL } = require("../../../utilities")
|
||||
const { DocumentTypes } = require("../../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const AWS = require("aws-sdk")
|
||||
const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1"
|
||||
|
||||
|
@ -44,7 +44,7 @@ async function getAppIdFromUrl(ctx) {
|
|||
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
|
||||
|
||||
// search prod apps for a url that matches, exclude dev where id is always used
|
||||
const apps = await getAllApps(CouchDB, { dev: false })
|
||||
const apps = await getAllApps({ dev: false })
|
||||
const app = apps.filter(
|
||||
a => a.url && a.url.toLowerCase() === possibleAppUrl
|
||||
)[0]
|
||||
|
@ -85,7 +85,7 @@ exports.uploadFile = async function (ctx) {
|
|||
exports.serveApp = async function (ctx) {
|
||||
let appId = await getAppIdFromUrl(ctx)
|
||||
const App = require("./templates/BudibaseApp.svelte").default
|
||||
const db = new CouchDB(appId, { skip_setup: true })
|
||||
const db = getAppDB({ skip_setup: true })
|
||||
const appInfo = await db.get(DocumentTypes.APP_METADATA)
|
||||
|
||||
const { head, html, css } = App.render({
|
||||
|
@ -111,7 +111,7 @@ exports.serveClientLibrary = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.getSignedUploadURL = async function (ctx) {
|
||||
const database = new CouchDB(ctx.appId)
|
||||
const database = getAppDB()
|
||||
|
||||
// Ensure datasource is valid
|
||||
let datasource
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const {
|
||||
buildExternalTableId,
|
||||
breakExternalTableId,
|
||||
|
@ -19,6 +18,7 @@ const { makeExternalQuery } = require("../../../integrations/base/utils")
|
|||
const { cloneDeep } = require("lodash/fp")
|
||||
const csvParser = require("../../../utilities/csvParser")
|
||||
const { handleRequest } = require("../row/external")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
async function makeTableRequest(
|
||||
datasource,
|
||||
|
@ -159,7 +159,6 @@ function isRelationshipSetup(column) {
|
|||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const table = ctx.request.body
|
||||
// can't do this right now
|
||||
delete table.dataImport
|
||||
|
@ -176,14 +175,14 @@ exports.save = async function (ctx) {
|
|||
|
||||
let oldTable
|
||||
if (ctx.request.body && ctx.request.body._id) {
|
||||
oldTable = await getTable(appId, ctx.request.body._id)
|
||||
oldTable = await getTable(ctx.request.body._id)
|
||||
}
|
||||
|
||||
if (hasTypeChanged(tableToSave, oldTable)) {
|
||||
ctx.throw(400, "A column type has changed.")
|
||||
}
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
const oldTables = cloneDeep(datasource.entities)
|
||||
const tables = datasource.entities
|
||||
|
@ -267,14 +266,13 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const tableToDelete = await getTable(appId, ctx.params.tableId)
|
||||
const tableToDelete = await getTable(ctx.params.tableId)
|
||||
if (!tableToDelete || !tableToDelete.created) {
|
||||
ctx.throw(400, "Cannot delete tables which weren't created in Budibase.")
|
||||
}
|
||||
const datasourceId = getDatasourceId(tableToDelete)
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
const tables = datasource.entities
|
||||
|
||||
|
@ -290,8 +288,7 @@ exports.destroy = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.bulkImport = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const table = await getTable(appId, ctx.params.tableId)
|
||||
const table = await getTable(ctx.params.tableId)
|
||||
const { dataImport } = ctx.request.body
|
||||
if (!dataImport || !dataImport.schema || !dataImport.csvString) {
|
||||
ctx.throw(400, "Provided data import information is invalid.")
|
||||
|
@ -300,7 +297,7 @@ exports.bulkImport = async function (ctx) {
|
|||
...dataImport,
|
||||
existingTable: table,
|
||||
})
|
||||
await handleRequest(appId, DataSourceOperation.BULK_CREATE, table._id, {
|
||||
await handleRequest(DataSourceOperation.BULK_CREATE, table._id, {
|
||||
rows,
|
||||
})
|
||||
return table
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const internal = require("./internal")
|
||||
const external = require("./external")
|
||||
const csvParser = require("../../../utilities/csvParser")
|
||||
|
@ -9,6 +8,7 @@ const {
|
|||
BudibaseInternalDB,
|
||||
} = require("../../../db/utils")
|
||||
const { getTable } = require("./utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
function pickApi({ tableId, table }) {
|
||||
if (table && !tableId) {
|
||||
|
@ -24,7 +24,7 @@ function pickApi({ tableId, table }) {
|
|||
|
||||
// covers both internal and external
|
||||
exports.fetch = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
|
||||
const internalTables = await db.allDocs(
|
||||
getTableParams(null, {
|
||||
|
@ -63,7 +63,7 @@ exports.fetch = async function (ctx) {
|
|||
|
||||
exports.find = async function (ctx) {
|
||||
const tableId = ctx.params.id
|
||||
ctx.body = await getTable(ctx.appId, tableId)
|
||||
ctx.body = await getTable(tableId)
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
|
@ -102,7 +102,7 @@ exports.validateCSVSchema = async function (ctx) {
|
|||
const { csvString, schema = {}, tableId } = ctx.request.body
|
||||
let existingTable
|
||||
if (tableId) {
|
||||
existingTable = await getTable(ctx.appId, tableId)
|
||||
existingTable = await getTable(tableId)
|
||||
}
|
||||
let result = await csvParser.parse(csvString, schema)
|
||||
if (existingTable) {
|
||||
|
|
|
@ -34,8 +34,7 @@ exports.save = async function (ctx) {
|
|||
// saving a table is a complex operation, involving many different steps, this
|
||||
// has been broken out into a utility to make it more obvious/easier to manipulate
|
||||
const tableSaveFunctions = new TableSaveFunctions({
|
||||
db,
|
||||
ctx,
|
||||
user: ctx.user,
|
||||
oldTable,
|
||||
dataImport,
|
||||
})
|
||||
|
@ -145,9 +144,8 @@ exports.destroy = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.bulkImport = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const table = await getTable(appId, ctx.params.tableId)
|
||||
const table = await getTable(ctx.params.tableId)
|
||||
const { dataImport } = ctx.request.body
|
||||
await handleDataImport(appId, ctx.user, table, dataImport)
|
||||
await handleDataImport(ctx.user, table, dataImport)
|
||||
return table
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const csvParser = require("../../../utilities/csvParser")
|
||||
const {
|
||||
getRowParams,
|
||||
|
@ -17,8 +16,10 @@ const {
|
|||
const { getViews, saveView } = require("../view/utils")
|
||||
const viewTemplate = require("../view/viewBuilder")
|
||||
const usageQuota = require("../../../utilities/usageQuota")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
|
||||
exports.checkForColumnUpdates = async (oldTable, updatedTable) => {
|
||||
const db = getAppDB()
|
||||
let updatedRows = []
|
||||
const rename = updatedTable._rename
|
||||
let deletedColumns = []
|
||||
|
@ -46,7 +47,7 @@ exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
|
|||
})
|
||||
|
||||
// Update views
|
||||
await exports.checkForViewUpdates(db, updatedTable, rename, deletedColumns)
|
||||
await exports.checkForViewUpdates(updatedTable, rename, deletedColumns)
|
||||
delete updatedTable._rename
|
||||
}
|
||||
return { rows: updatedRows, table: updatedTable }
|
||||
|
@ -73,12 +74,12 @@ exports.makeSureTableUpToDate = (table, tableToSave) => {
|
|||
return tableToSave
|
||||
}
|
||||
|
||||
exports.handleDataImport = async (appId, user, table, dataImport) => {
|
||||
exports.handleDataImport = async (user, table, dataImport) => {
|
||||
if (!dataImport || !dataImport.csvString) {
|
||||
return table
|
||||
}
|
||||
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
// Populate the table with rows imported from CSV in a bulk update
|
||||
const data = await csvParser.transform({
|
||||
...dataImport,
|
||||
|
@ -123,8 +124,8 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
|||
return table
|
||||
}
|
||||
|
||||
exports.handleSearchIndexes = async (appId, table) => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.handleSearchIndexes = async table => {
|
||||
const db = getAppDB()
|
||||
// create relevant search indexes
|
||||
if (table.indexes && table.indexes.length > 0) {
|
||||
const currentIndexes = await db.getIndexes()
|
||||
|
@ -181,12 +182,9 @@ exports.checkStaticTables = table => {
|
|||
}
|
||||
|
||||
class TableSaveFunctions {
|
||||
constructor({ db, ctx, oldTable, dataImport }) {
|
||||
this.db = db
|
||||
this.ctx = ctx
|
||||
if (this.ctx && this.ctx.user) {
|
||||
this.appId = this.ctx.appId
|
||||
}
|
||||
constructor({ user, oldTable, dataImport }) {
|
||||
this.db = getAppDB()
|
||||
this.user = user
|
||||
this.oldTable = oldTable
|
||||
this.dataImport = dataImport
|
||||
// any rows that need updated
|
||||
|
@ -204,24 +202,15 @@ class TableSaveFunctions {
|
|||
|
||||
// when confirmed valid
|
||||
async mid(table) {
|
||||
let response = await exports.checkForColumnUpdates(
|
||||
this.db,
|
||||
this.oldTable,
|
||||
table
|
||||
)
|
||||
let response = await exports.checkForColumnUpdates(this.oldTable, table)
|
||||
this.rows = this.rows.concat(response.rows)
|
||||
return table
|
||||
}
|
||||
|
||||
// after saving
|
||||
async after(table) {
|
||||
table = await exports.handleSearchIndexes(this.appId, table)
|
||||
table = await exports.handleDataImport(
|
||||
this.appId,
|
||||
this.ctx.user,
|
||||
table,
|
||||
this.dataImport
|
||||
)
|
||||
table = await exports.handleSearchIndexes(table)
|
||||
table = await exports.handleDataImport(this.user, table, this.dataImport)
|
||||
return table
|
||||
}
|
||||
|
||||
|
@ -230,8 +219,8 @@ class TableSaveFunctions {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getAllExternalTables = async (appId, datasourceId) => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.getAllExternalTables = async datasourceId => {
|
||||
const db = getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
if (!datasource || !datasource.entities) {
|
||||
throw "Datasource is not configured fully."
|
||||
|
@ -239,25 +228,25 @@ exports.getAllExternalTables = async (appId, datasourceId) => {
|
|||
return datasource.entities
|
||||
}
|
||||
|
||||
exports.getExternalTable = async (appId, datasourceId, tableName) => {
|
||||
const entities = await exports.getAllExternalTables(appId, datasourceId)
|
||||
exports.getExternalTable = async (datasourceId, tableName) => {
|
||||
const entities = await exports.getAllExternalTables(datasourceId)
|
||||
return entities[tableName]
|
||||
}
|
||||
|
||||
exports.getTable = async (appId, tableId) => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.getTable = async tableId => {
|
||||
const db = getAppDB()
|
||||
if (isExternalTable(tableId)) {
|
||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
const datasource = await db.get(datasourceId)
|
||||
const table = await exports.getExternalTable(appId, datasourceId, tableName)
|
||||
const table = await exports.getExternalTable(datasourceId, tableName)
|
||||
return { ...table, sql: isSQL(datasource) }
|
||||
} else {
|
||||
return db.get(tableId)
|
||||
}
|
||||
}
|
||||
|
||||
exports.checkForViewUpdates = async (db, table, rename, deletedColumns) => {
|
||||
const views = await getViews(db)
|
||||
exports.checkForViewUpdates = async (table, rename, deletedColumns) => {
|
||||
const views = await getViews()
|
||||
const tableViews = views.filter(view => view.meta.tableId === table._id)
|
||||
|
||||
// Check each table view to see if impacted by this table action
|
||||
|
@ -319,7 +308,7 @@ exports.checkForViewUpdates = async (db, table, rename, deletedColumns) => {
|
|||
// Update view if required
|
||||
if (needsUpdated) {
|
||||
const newViewTemplate = viewTemplate(view.meta)
|
||||
await saveView(db, null, view.name, newViewTemplate)
|
||||
await saveView(null, view.name, newViewTemplate)
|
||||
if (!newViewTemplate.meta.schema) {
|
||||
newViewTemplate.meta.schema = table.schema
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../db")
|
||||
const {
|
||||
generateUserMetadataID,
|
||||
getUserMetadataParams,
|
||||
|
@ -15,8 +14,10 @@ const {
|
|||
} = require("@budibase/backend-core/db")
|
||||
const { doesDatabaseExist } = require("../../utilities")
|
||||
const { UserStatus } = require("@budibase/backend-core/constants")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
async function rawMetadata(db) {
|
||||
async function rawMetadata() {
|
||||
const db = getAppDB()
|
||||
return (
|
||||
await db.allDocs(
|
||||
getUserMetadataParams(null, {
|
||||
|
@ -54,13 +55,10 @@ function combineMetadataAndUser(user, metadata) {
|
|||
return null
|
||||
}
|
||||
|
||||
exports.syncGlobalUsers = async appId => {
|
||||
exports.syncGlobalUsers = async () => {
|
||||
// sync user metadata
|
||||
const db = new CouchDB(appId)
|
||||
const [users, metadata] = await Promise.all([
|
||||
getGlobalUsers(appId),
|
||||
rawMetadata(db),
|
||||
])
|
||||
const db = getAppDB()
|
||||
const [users, metadata] = await Promise.all([getGlobalUsers(), rawMetadata()])
|
||||
const toWrite = []
|
||||
for (let user of users) {
|
||||
const combined = await combineMetadataAndUser(user, metadata)
|
||||
|
@ -94,7 +92,7 @@ exports.syncUser = async function (ctx) {
|
|||
let prodAppIds
|
||||
// if they are a builder then get all production app IDs
|
||||
if ((user.builder && user.builder.global) || deleting) {
|
||||
prodAppIds = await getDeployedAppIDs(CouchDB)
|
||||
prodAppIds = await getDeployedAppIDs()
|
||||
} else {
|
||||
prodAppIds = Object.entries(roles)
|
||||
.filter(entry => entry[1] !== BUILTIN_ROLE_IDS.PUBLIC)
|
||||
|
@ -107,7 +105,7 @@ exports.syncUser = async function (ctx) {
|
|||
if (!(await doesDatabaseExist(appId))) {
|
||||
continue
|
||||
}
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const metadataId = generateUserMetadataID(userId)
|
||||
let metadata
|
||||
try {
|
||||
|
@ -143,8 +141,8 @@ exports.syncUser = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.fetchMetadata = async function (ctx) {
|
||||
const database = new CouchDB(ctx.appId)
|
||||
const global = await getGlobalUsers(ctx.appId)
|
||||
const database = getAppDB()
|
||||
const global = await getGlobalUsers()
|
||||
const metadata = await rawMetadata(database)
|
||||
const users = []
|
||||
for (let user of global) {
|
||||
|
@ -171,8 +169,7 @@ exports.updateSelfMetadata = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.updateMetadata = async function (ctx) {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const user = ctx.request.body
|
||||
// this isn't applicable to the user
|
||||
delete user.roles
|
||||
|
@ -184,7 +181,7 @@ exports.updateMetadata = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.destroyMetadata = async function (ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
try {
|
||||
const dbUser = await db.get(ctx.params.id)
|
||||
await db.remove(dbUser._id, dbUser._rev)
|
||||
|
@ -207,7 +204,7 @@ exports.setFlag = async function (ctx) {
|
|||
ctx.throw(400, "Must supply a 'flag' field in request body.")
|
||||
}
|
||||
const flagDocId = generateUserFlagID(userId)
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
let doc
|
||||
try {
|
||||
doc = await db.get(flagDocId)
|
||||
|
@ -222,7 +219,7 @@ exports.setFlag = async function (ctx) {
|
|||
exports.getFlags = async function (ctx) {
|
||||
const userId = ctx.user._id
|
||||
const docId = generateUserFlagID(userId)
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
let doc
|
||||
try {
|
||||
doc = await db.get(docId)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const viewTemplate = require("./viewBuilder")
|
||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
||||
const exporters = require("./exporters")
|
||||
|
@ -6,14 +5,14 @@ const { saveView, getView, getViews, deleteView } = require("./utils")
|
|||
const { fetchView } = require("../row")
|
||||
const { getTable } = require("../table/utils")
|
||||
const { FieldTypes } = require("../../../constants")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
ctx.body = await getViews(db)
|
||||
ctx.body = await getViews()
|
||||
}
|
||||
|
||||
exports.save = async ctx => {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const { originalName, ...viewToSave } = ctx.request.body
|
||||
const view = viewTemplate(viewToSave)
|
||||
|
||||
|
@ -21,7 +20,7 @@ exports.save = async ctx => {
|
|||
ctx.throw(400, "Cannot create view without a name")
|
||||
}
|
||||
|
||||
await saveView(db, originalName, viewToSave.name, view)
|
||||
await saveView(originalName, viewToSave.name, view)
|
||||
|
||||
// add views to table document
|
||||
const table = await db.get(ctx.request.body.tableId)
|
||||
|
@ -42,9 +41,9 @@ exports.save = async ctx => {
|
|||
}
|
||||
|
||||
exports.destroy = async ctx => {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
const viewName = decodeURI(ctx.params.viewName)
|
||||
const view = await deleteView(db, viewName)
|
||||
const view = await deleteView(viewName)
|
||||
const table = await db.get(view.meta.tableId)
|
||||
delete table.views[viewName]
|
||||
await db.put(table)
|
||||
|
@ -53,9 +52,8 @@ exports.destroy = async ctx => {
|
|||
}
|
||||
|
||||
exports.exportView = async ctx => {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const viewName = decodeURI(ctx.query.view)
|
||||
const view = await getView(db, viewName)
|
||||
const view = await getView(viewName)
|
||||
|
||||
const format = ctx.query.format
|
||||
if (!format || !Object.values(exporters.ExportFormats).includes(format)) {
|
||||
|
@ -83,7 +81,7 @@ exports.exportView = async ctx => {
|
|||
let schema = view && view.meta && view.meta.schema
|
||||
if (!schema) {
|
||||
const tableId = ctx.params.tableId || view.meta.tableId
|
||||
const table = await getTable(ctx.appId, tableId)
|
||||
const table = await getTable(tableId)
|
||||
schema = table.schema
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,10 @@ const {
|
|||
SEPARATOR,
|
||||
} = require("../../../db/utils")
|
||||
const env = require("../../../environment")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.getView = async (db, viewName) => {
|
||||
exports.getView = async viewName => {
|
||||
const db = getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
return designDoc.views[viewName]
|
||||
|
@ -22,7 +24,8 @@ exports.getView = async (db, viewName) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getViews = async db => {
|
||||
exports.getViews = async () => {
|
||||
const db = getAppDB()
|
||||
const response = []
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
|
@ -54,7 +57,8 @@ exports.getViews = async db => {
|
|||
return response
|
||||
}
|
||||
|
||||
exports.saveView = async (db, originalName, viewName, viewTemplate) => {
|
||||
exports.saveView = async (originalName, viewName, viewTemplate) => {
|
||||
const db = getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
designDoc.views = {
|
||||
|
@ -91,7 +95,8 @@ exports.saveView = async (db, originalName, viewName, viewTemplate) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.deleteView = async (db, viewName) => {
|
||||
exports.deleteView = async viewName => {
|
||||
const db = getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = designDoc.views[viewName]
|
||||
|
|
|
@ -82,7 +82,6 @@ describe("run misc tests", () => {
|
|||
dataImport.schema[col] = { type: "string" }
|
||||
}
|
||||
await tableUtils.handleDataImport(
|
||||
config.getAppId(),
|
||||
{ userId: "test" },
|
||||
table,
|
||||
dataImport
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const rowController = require("../../../controllers/row")
|
||||
const appController = require("../../../controllers/application")
|
||||
const CouchDB = require("../../../../db")
|
||||
const { AppStatus } = require("../../../../db/utils")
|
||||
const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles")
|
||||
const { TENANT_ID } = require("../../../../tests/utilities/structures")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
function Request(appId, params) {
|
||||
this.appId = appId
|
||||
|
@ -96,8 +96,8 @@ exports.checkPermissionsEndpoint = async ({
|
|||
.expect(403)
|
||||
}
|
||||
|
||||
exports.getDB = config => {
|
||||
return new CouchDB(config.getAppId())
|
||||
exports.getDB = () => {
|
||||
return getAppDB()
|
||||
}
|
||||
|
||||
exports.testAutomation = async (config, automation) => {
|
||||
|
|
|
@ -53,13 +53,12 @@ exports.cleanInputValues = (inputs, schema) => {
|
|||
* the automation but is instead part of the Table/Table. This function will get the table schema and use it to instead
|
||||
* perform the cleanInputValues function on the input row.
|
||||
*
|
||||
* @param {string} appId The instance which the Table/Table is contained under.
|
||||
* @param {string} tableId The ID of the Table/Table which the schema is to be retrieved for.
|
||||
* @param {object} row The input row structure which requires clean-up after having been through template statements.
|
||||
* @returns {Promise<Object>} The cleaned up rows object, will should now have all the required primitive types.
|
||||
*/
|
||||
exports.cleanUpRow = async (appId, tableId, row) => {
|
||||
let table = await getTable(appId, tableId)
|
||||
exports.cleanUpRow = async (tableId, row) => {
|
||||
let table = await getTable(tableId)
|
||||
return exports.cleanInputValues(row, { properties: table.schema })
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ exports.run = async function ({ inputs, appId, emitter }) {
|
|||
|
||||
try {
|
||||
inputs.row = await automationUtils.cleanUpRow(
|
||||
appId,
|
||||
inputs.row.tableId,
|
||||
inputs.row
|
||||
)
|
||||
|
|
|
@ -87,7 +87,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
|
|||
|
||||
try {
|
||||
if (tableId) {
|
||||
inputs.row = await automationUtils.cleanUpRow(appId, tableId, inputs.row)
|
||||
inputs.row = await automationUtils.cleanUpRow(tableId, inputs.row)
|
||||
}
|
||||
await rowController.patch(ctx)
|
||||
return {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
const CouchDB = require("../index")
|
||||
const { IncludeDocs, getLinkDocuments } = require("./linkUtils")
|
||||
const {
|
||||
generateLinkID,
|
||||
|
@ -7,6 +6,7 @@ const {
|
|||
} = require("../utils")
|
||||
const Sentry = require("@sentry/node")
|
||||
const { FieldTypes, RelationshipTypes } = require("../../constants")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
/**
|
||||
* Creates a new link document structure which can be put to the database. It is important to
|
||||
|
@ -52,9 +52,8 @@ function LinkDocument(
|
|||
}
|
||||
|
||||
class LinkController {
|
||||
constructor({ appId, tableId, row, table, oldTable }) {
|
||||
this._appId = appId
|
||||
this._db = new CouchDB(appId)
|
||||
constructor({ tableId, row, table, oldTable }) {
|
||||
this._db = getAppDB()
|
||||
this._tableId = tableId
|
||||
this._row = row
|
||||
this._table = table
|
||||
|
@ -99,7 +98,6 @@ class LinkController {
|
|||
*/
|
||||
getRowLinkDocs(rowId) {
|
||||
return getLinkDocuments({
|
||||
appId: this._appId,
|
||||
tableId: this._tableId,
|
||||
rowId,
|
||||
includeDocs: IncludeDocs.INCLUDE,
|
||||
|
@ -111,7 +109,6 @@ class LinkController {
|
|||
*/
|
||||
getTableLinkDocs() {
|
||||
return getLinkDocuments({
|
||||
appId: this._appId,
|
||||
tableId: this._tableId,
|
||||
includeDocs: IncludeDocs.INCLUDE,
|
||||
})
|
||||
|
@ -230,7 +227,6 @@ class LinkController {
|
|||
if (linkedSchema.relationshipType === RelationshipTypes.ONE_TO_MANY) {
|
||||
let links = (
|
||||
await getLinkDocuments({
|
||||
appId: this._appId,
|
||||
tableId: field.tableId,
|
||||
rowId: linkId,
|
||||
includeDocs: IncludeDocs.EXCLUDE,
|
||||
|
|
|
@ -9,12 +9,12 @@ const {
|
|||
getLinkedTable,
|
||||
} = require("./linkUtils")
|
||||
const { flatten } = require("lodash")
|
||||
const CouchDB = require("../../db")
|
||||
const { FieldTypes } = require("../../constants")
|
||||
const { getMultiIDParams, USER_METDATA_PREFIX } = require("../../db/utils")
|
||||
const { partition } = require("lodash")
|
||||
const { getGlobalUsersFromMetadata } = require("../../utilities/global")
|
||||
const { processFormulas } = require("../../utilities/rowProcessor/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
/**
|
||||
* This functionality makes sure that when rows with links are created, updated or deleted they are processed
|
||||
|
@ -48,14 +48,13 @@ function clearRelationshipFields(table, rows) {
|
|||
return rows
|
||||
}
|
||||
|
||||
async function getLinksForRows(appId, rows) {
|
||||
async function getLinksForRows(rows) {
|
||||
const tableIds = [...new Set(rows.map(el => el.tableId))]
|
||||
// start by getting all the link values for performance reasons
|
||||
const responses = flatten(
|
||||
await Promise.all(
|
||||
tableIds.map(tableId =>
|
||||
getLinkDocuments({
|
||||
appId,
|
||||
tableId: tableId,
|
||||
includeDocs: IncludeDocs.EXCLUDE,
|
||||
})
|
||||
|
@ -72,9 +71,9 @@ async function getLinksForRows(appId, rows) {
|
|||
)
|
||||
}
|
||||
|
||||
async function getFullLinkedDocs(ctx, appId, links) {
|
||||
async function getFullLinkedDocs(links) {
|
||||
// create DBs
|
||||
const db = new CouchDB(appId)
|
||||
const db = getAppDB()
|
||||
const linkedRowIds = links.map(link => link.id)
|
||||
const uniqueRowIds = [...new Set(linkedRowIds)]
|
||||
let dbRows = (await db.allDocs(getMultiIDParams(uniqueRowIds))).rows.map(
|
||||
|
@ -88,7 +87,7 @@ async function getFullLinkedDocs(ctx, appId, links) {
|
|||
let [users, other] = partition(linked, linkRow =>
|
||||
linkRow._id.startsWith(USER_METDATA_PREFIX)
|
||||
)
|
||||
users = await getGlobalUsersFromMetadata(appId, users)
|
||||
users = await getGlobalUsersFromMetadata(users)
|
||||
return [...other, ...users]
|
||||
}
|
||||
|
||||
|
@ -96,7 +95,6 @@ async function getFullLinkedDocs(ctx, appId, links) {
|
|||
* Update link documents for a row or table - this is to be called by the API controller when a change is occurring.
|
||||
* @param {string} args.eventType states what type of change which is occurring, means this can be expanded upon in the
|
||||
* future quite easily (all updates go through one function).
|
||||
* @param {string} args.appId The ID of the instance in which the change is occurring.
|
||||
* @param {string} args.tableId The ID of the of the table which is being changed.
|
||||
* @param {object|null} args.row The row which is changing, e.g. created, updated or deleted.
|
||||
* @param {object|null} args.table If the table has already been retrieved this can be used to reduce database gets.
|
||||
|
@ -105,11 +103,8 @@ async function getFullLinkedDocs(ctx, appId, links) {
|
|||
* row operations and the table for table operations.
|
||||
*/
|
||||
exports.updateLinks = async function (args) {
|
||||
const { eventType, appId, row, tableId, table, oldTable } = args
|
||||
const { eventType, row, tableId, table, oldTable } = args
|
||||
const baseReturnObj = row == null ? table : row
|
||||
if (appId == null) {
|
||||
throw "Cannot operate without an instance ID."
|
||||
}
|
||||
// make sure table ID is set
|
||||
if (tableId == null && table != null) {
|
||||
args.tableId = table._id
|
||||
|
@ -146,27 +141,23 @@ exports.updateLinks = async function (args) {
|
|||
/**
|
||||
* Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
|
||||
* This is required for formula fields, this may only be utilised internally (for now).
|
||||
* @param {object} ctx The request which is looking for rows.
|
||||
* @param {object} table The table from which the rows originated.
|
||||
* @param {array<object>} rows The rows which are to be enriched.
|
||||
* @return {Promise<*>} returns the rows with all of the enriched relationships on it.
|
||||
*/
|
||||
exports.attachFullLinkedDocs = async (ctx, table, rows) => {
|
||||
const appId = ctx.appId
|
||||
exports.attachFullLinkedDocs = async (table, rows) => {
|
||||
const linkedTableIds = getLinkedTableIDs(table)
|
||||
if (linkedTableIds.length === 0) {
|
||||
return rows
|
||||
}
|
||||
// create DBs
|
||||
const db = new CouchDB(appId)
|
||||
// get all the links
|
||||
const links = (await getLinksForRows(appId, rows)).filter(link =>
|
||||
const links = (await getLinksForRows(rows)).filter(link =>
|
||||
rows.some(row => row._id === link.thisId)
|
||||
)
|
||||
// clear any existing links that could be dupe'd
|
||||
rows = clearRelationshipFields(table, rows)
|
||||
// now get the docs and combine into the rows
|
||||
let linked = await getFullLinkedDocs(ctx, appId, links)
|
||||
let linked = await getFullLinkedDocs(links)
|
||||
const linkedTables = []
|
||||
for (let row of rows) {
|
||||
for (let link of links.filter(link => link.thisId === row._id)) {
|
||||
|
@ -177,11 +168,7 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
|
|||
if (linkedRow) {
|
||||
const linkedTableId =
|
||||
linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
|
||||
const linkedTable = await getLinkedTable(
|
||||
db,
|
||||
linkedTableId,
|
||||
linkedTables
|
||||
)
|
||||
const linkedTable = await getLinkedTable(linkedTableId, linkedTables)
|
||||
if (linkedTable) {
|
||||
row[link.fieldName].push(processFormulas(linkedTable, linkedRow))
|
||||
}
|
||||
|
@ -193,18 +180,16 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
|
|||
|
||||
/**
|
||||
* This function will take the given enriched rows and squash the links to only contain the primary display field.
|
||||
* @param {string} appId The app in which the tables/rows/links exist.
|
||||
* @param {object} table The table from which the rows originated.
|
||||
* @param {array<object>} enriched The pre-enriched rows (full docs) which are to be squashed.
|
||||
* @returns {Promise<Array>} The rows after having their links squashed to only contain the ID and primary display.
|
||||
*/
|
||||
exports.squashLinksToPrimaryDisplay = async (appId, table, enriched) => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.squashLinksToPrimaryDisplay = async (table, enriched) => {
|
||||
// will populate this as we find them
|
||||
const linkedTables = [table]
|
||||
for (let row of enriched) {
|
||||
// this only fetches the table if its not already in array
|
||||
const rowTable = await getLinkedTable(db, row.tableId, linkedTables)
|
||||
const rowTable = await getLinkedTable(row.tableId, linkedTables)
|
||||
for (let [column, schema] of Object.entries(rowTable.schema)) {
|
||||
if (schema.type !== FieldTypes.LINK || !Array.isArray(row[column])) {
|
||||
continue
|
||||
|
@ -212,7 +197,7 @@ exports.squashLinksToPrimaryDisplay = async (appId, table, enriched) => {
|
|||
const newLinks = []
|
||||
for (let link of row[column]) {
|
||||
const linkTblId = link.tableId || getRelatedTableForField(table, column)
|
||||
const linkedTable = await getLinkedTable(db, linkTblId, linkedTables)
|
||||
const linkedTable = await getLinkedTable(linkTblId, linkedTables)
|
||||
const obj = { _id: link._id }
|
||||
if (link[linkedTable.primaryDisplay]) {
|
||||
obj.primaryDisplay = link[linkedTable.primaryDisplay]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const CouchDB = require("../index")
|
||||
const Sentry = require("@sentry/node")
|
||||
const { ViewNames, getQueryIndex } = require("../utils")
|
||||
const { FieldTypes } = require("../../constants")
|
||||
const { createLinkView } = require("../views/staticViews")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
/**
|
||||
* Only needed so that boolean parameters are being used for includeDocs
|
||||
|
@ -17,7 +17,6 @@ exports.createLinkView = createLinkView
|
|||
|
||||
/**
|
||||
* Gets the linking documents, not the linked documents themselves.
|
||||
* @param {string} args.appId The instance in which we are searching for linked rows.
|
||||
* @param {string} args.tableId The table which we are searching for linked rows against.
|
||||
* @param {string|null} args.fieldName The name of column/field which is being altered, only looking for
|
||||
* linking documents that are related to it. If this is not specified then the table level will be assumed.
|
||||
|
@ -30,8 +29,8 @@ exports.createLinkView = createLinkView
|
|||
* (if any).
|
||||
*/
|
||||
exports.getLinkDocuments = async function (args) {
|
||||
const { appId, tableId, rowId, includeDocs } = args
|
||||
const db = new CouchDB(appId)
|
||||
const { tableId, rowId, includeDocs } = args
|
||||
const db = getAppDB()
|
||||
let params
|
||||
if (rowId != null) {
|
||||
params = { key: [tableId, rowId] }
|
||||
|
@ -68,7 +67,7 @@ exports.getLinkDocuments = async function (args) {
|
|||
} catch (err) {
|
||||
// check if the view doesn't exist, it should for all new instances
|
||||
if (err != null && err.name === "not_found") {
|
||||
await exports.createLinkView(appId)
|
||||
await exports.createLinkView()
|
||||
return exports.getLinkDocuments(arguments[0])
|
||||
} else {
|
||||
/* istanbul ignore next */
|
||||
|
@ -89,7 +88,8 @@ exports.getLinkedTableIDs = table => {
|
|||
.map(column => column.tableId)
|
||||
}
|
||||
|
||||
exports.getLinkedTable = async (db, id, tables) => {
|
||||
exports.getLinkedTable = async (id, tables) => {
|
||||
const db = getAppDB()
|
||||
let linkedTable = tables.find(table => table._id === id)
|
||||
if (linkedTable) {
|
||||
return linkedTable
|
||||
|
|
|
@ -20,7 +20,6 @@ describe("test the link controller", () => {
|
|||
|
||||
function createLinkController(table, row = null, oldTable = null) {
|
||||
const linkConfig = {
|
||||
appId: config.getAppId(),
|
||||
tableId: table._id,
|
||||
table,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
const TestConfig = require("../../tests/utilities/TestConfiguration")
|
||||
const { basicTable, basicLinkedRow } = require("../../tests/utilities/structures")
|
||||
const { basicTable } = require("../../tests/utilities/structures")
|
||||
const linkUtils = require("../linkedRows/linkUtils")
|
||||
const links = require("../linkedRows")
|
||||
const CouchDB = require("../index")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
describe("test link functionality", () => {
|
||||
const config = new TestConfig(false)
|
||||
|
@ -11,18 +11,18 @@ describe("test link functionality", () => {
|
|||
let db, table
|
||||
beforeEach(async () => {
|
||||
await config.init()
|
||||
db = new CouchDB(config.getAppId())
|
||||
db = getAppDB()
|
||||
table = await config.createTable()
|
||||
})
|
||||
|
||||
it("should be able to retrieve a linked table from a list", async () => {
|
||||
const retrieved = await linkUtils.getLinkedTable(db, table._id, [table])
|
||||
const retrieved = await linkUtils.getLinkedTable(table._id, [table])
|
||||
expect(retrieved._id).toBe(table._id)
|
||||
})
|
||||
|
||||
it("should be able to retrieve a table from DB and update list", async () => {
|
||||
const tables = []
|
||||
const retrieved = await linkUtils.getLinkedTable(db, table._id, tables)
|
||||
const retrieved = await linkUtils.getLinkedTable(table._id, tables)
|
||||
expect(retrieved._id).toBe(table._id)
|
||||
expect(tables[0]).toBeDefined()
|
||||
})
|
||||
|
@ -51,7 +51,6 @@ describe("test link functionality", () => {
|
|||
const db = new CouchDB("test")
|
||||
await db.put({ _id: "_design/database", views: {} })
|
||||
const output = await linkUtils.getLinkDocuments({
|
||||
appId: "test",
|
||||
tableId: "test",
|
||||
rowId: "test",
|
||||
includeDocs: false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const CouchDB = require("../index")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const {
|
||||
DocumentTypes,
|
||||
SEPARATOR,
|
||||
|
@ -21,12 +21,11 @@ const SCREEN_PREFIX = DocumentTypes.SCREEN + SEPARATOR
|
|||
/**
|
||||
* Creates the link view for the instance, this will overwrite the existing one, but this should only
|
||||
* be called if it is found that the view does not exist.
|
||||
* @param {string} appId The instance to which the view should be added.
|
||||
* @returns {Promise<void>} The view now exists, please note that the next view of this query will actually build it,
|
||||
* so it may be slow.
|
||||
*/
|
||||
exports.createLinkView = async appId => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.createLinkView = async () => {
|
||||
const db = getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = {
|
||||
map: function (doc) {
|
||||
|
@ -57,8 +56,8 @@ exports.createLinkView = async appId => {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createRoutingView = async appId => {
|
||||
const db = new CouchDB(appId)
|
||||
exports.createRoutingView = async () => {
|
||||
const db = getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
|
@ -78,8 +77,8 @@ exports.createRoutingView = async appId => {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
async function searchIndex(appId, indexName, fnString) {
|
||||
const db = new CouchDB(appId)
|
||||
async function searchIndex(indexName, fnString) {
|
||||
const db = getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
designDoc.indexes = {
|
||||
[indexName]: {
|
||||
|
@ -90,9 +89,8 @@ async function searchIndex(appId, indexName, fnString) {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createAllSearchIndex = async appId => {
|
||||
exports.createAllSearchIndex = async () => {
|
||||
await searchIndex(
|
||||
appId,
|
||||
SearchIndexes.ROWS,
|
||||
function (doc) {
|
||||
function idx(input, prev) {
|
||||
|
|
|
@ -52,7 +52,10 @@ export function buildExternalTableId(datasourceId: string, tableName: string) {
|
|||
return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`
|
||||
}
|
||||
|
||||
export function breakExternalTableId(tableId: string) {
|
||||
export function breakExternalTableId(tableId: string | undefined) {
|
||||
if (!tableId) {
|
||||
return {}
|
||||
}
|
||||
const parts = tableId.split(DOUBLE_SEPARATOR)
|
||||
let tableName = parts.pop()
|
||||
// if they need joined
|
||||
|
|
|
@ -43,13 +43,13 @@ module.exports =
|
|||
|
||||
// need to check this first, in-case public access, don't check authed until last
|
||||
const roleId = ctx.roleId || BUILTIN_ROLE_IDS.PUBLIC
|
||||
const hierarchy = await getUserRoleHierarchy(ctx.appId, roleId, {
|
||||
const hierarchy = await getUserRoleHierarchy(roleId, {
|
||||
idOnly: false,
|
||||
})
|
||||
const permError = "User does not have permission"
|
||||
let possibleRoleIds = []
|
||||
if (hasResource(ctx)) {
|
||||
possibleRoleIds = await getRequiredResourceRole(ctx.appId, permLevel, ctx)
|
||||
possibleRoleIds = await getRequiredResourceRole(permLevel, ctx)
|
||||
}
|
||||
// check if we found a role, if not fallback to base permissions
|
||||
if (possibleRoleIds.length > 0) {
|
||||
|
|
|
@ -11,7 +11,6 @@ const { generateUserMetadataID, isDevAppID } = require("../db/utils")
|
|||
const { dbExists } = require("@budibase/backend-core/db")
|
||||
const { isUserInAppTenant } = require("@budibase/backend-core/tenancy")
|
||||
const { getCachedSelf } = require("../utilities/global")
|
||||
const CouchDB = require("../db")
|
||||
const env = require("../environment")
|
||||
const { isWebhookEndpoint } = require("./utils")
|
||||
|
||||
|
@ -31,7 +30,7 @@ module.exports = async (ctx, next) => {
|
|||
// check the app exists referenced in cookie
|
||||
if (appCookie) {
|
||||
const appId = appCookie.appId
|
||||
const exists = await dbExists(CouchDB, appId)
|
||||
const exists = await dbExists(appId)
|
||||
if (!exists) {
|
||||
clearCookie(ctx, Cookies.CurrentApp)
|
||||
return next()
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
||||
const { getAllApps } = require("@budibase/backend-core/db")
|
||||
const CouchDB = require("../../db")
|
||||
const { getUsageQuotaDoc } = require("../../utilities/usageQuota")
|
||||
|
||||
exports.run = async () => {
|
||||
const db = getGlobalDB()
|
||||
// get app count
|
||||
const devApps = await getAllApps(CouchDB, { dev: true })
|
||||
const devApps = await getAllApps({ dev: true })
|
||||
const appCount = devApps ? devApps.length : 0
|
||||
|
||||
// sync app count
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
||||
const { getAllApps } = require("@budibase/backend-core/db")
|
||||
const CouchDB = require("../../db")
|
||||
const { getUsageQuotaDoc } = require("../../utilities/usageQuota")
|
||||
const { getUniqueRows } = require("../../utilities/usageQuota/rows")
|
||||
|
||||
exports.run = async () => {
|
||||
const db = getGlobalDB()
|
||||
// get all rows in all apps
|
||||
const allApps = await getAllApps(CouchDB, { all: true })
|
||||
const allApps = await getAllApps({ all: true })
|
||||
const appIds = allApps ? allApps.map(app => app.appId) : []
|
||||
const rows = await getUniqueRows(appIds)
|
||||
const rowCount = rows ? rows.length : 0
|
||||
|
|
|
@ -23,6 +23,7 @@ const { createASession } = require("@budibase/backend-core/sessions")
|
|||
const { user: userCache } = require("@budibase/backend-core/cache")
|
||||
const CouchDB = require("../../db")
|
||||
const newid = require("../../db/newid")
|
||||
const context = require("@budibase/backend-core/context")
|
||||
core.init(CouchDB)
|
||||
|
||||
const GLOBAL_USER_ID = "us_uuid1"
|
||||
|
@ -50,6 +51,7 @@ class TestConfiguration {
|
|||
}
|
||||
|
||||
async _req(config, params, controlFunc) {
|
||||
context.updateAppId(this.appId)
|
||||
const request = {}
|
||||
// fake cookies, we don't need them
|
||||
request.cookies = { set: () => {}, get: () => {} }
|
||||
|
@ -165,6 +167,7 @@ class TestConfiguration {
|
|||
// create dev app
|
||||
this.app = await this._req({ name: appName }, null, controllers.app.create)
|
||||
this.appId = this.app.appId
|
||||
context.updateAppId(this.appId)
|
||||
|
||||
// create production app
|
||||
this.prodApp = await this.deploy()
|
||||
|
|
|
@ -20,6 +20,7 @@ const {
|
|||
LINK_USER_METADATA_PREFIX,
|
||||
} = require("../../db/utils")
|
||||
const MemoryStream = require("memorystream")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
|
||||
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
||||
const NODE_MODULES_PATH = join(TOP_LEVEL_PATH, "node_modules")
|
||||
|
@ -251,7 +252,8 @@ exports.downloadTemplate = async (type, name) => {
|
|||
/**
|
||||
* Retrieves component libraries from object store (or tmp symlink if in local)
|
||||
*/
|
||||
exports.getComponentLibraryManifest = async (appId, library) => {
|
||||
exports.getComponentLibraryManifest = async library => {
|
||||
const appId = getAppId()
|
||||
const filename = "manifest.json"
|
||||
/* istanbul ignore next */
|
||||
// when testing in cypress and so on we need to get the package
|
||||
|
|
|
@ -11,8 +11,10 @@ const {
|
|||
isUserInAppTenant,
|
||||
} = require("@budibase/backend-core/tenancy")
|
||||
const env = require("../environment")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.updateAppRole = (appId, user) => {
|
||||
exports.updateAppRole = (user, { appId } = {}) => {
|
||||
appId = appId || getAppId()
|
||||
if (!user || !user.roles) {
|
||||
return user
|
||||
}
|
||||
|
@ -35,18 +37,18 @@ exports.updateAppRole = (appId, user) => {
|
|||
return user
|
||||
}
|
||||
|
||||
function processUser(appId, user) {
|
||||
function processUser(user, { appId } = {}) {
|
||||
if (user) {
|
||||
delete user.password
|
||||
}
|
||||
return exports.updateAppRole(appId, user)
|
||||
return exports.updateAppRole(user, { appId })
|
||||
}
|
||||
|
||||
exports.getCachedSelf = async (ctx, appId) => {
|
||||
// this has to be tenant aware, can't depend on the context to find it out
|
||||
// running some middlewares before the tenancy causes context to break
|
||||
const user = await userCache.getUser(ctx.user._id)
|
||||
return processUser(appId, user)
|
||||
return processUser(user, appId)
|
||||
}
|
||||
|
||||
exports.getRawGlobalUser = async userId => {
|
||||
|
@ -54,12 +56,13 @@ exports.getRawGlobalUser = async userId => {
|
|||
return db.get(getGlobalIDFromUserMetadataID(userId))
|
||||
}
|
||||
|
||||
exports.getGlobalUser = async (appId, userId) => {
|
||||
exports.getGlobalUser = async userId => {
|
||||
let user = await exports.getRawGlobalUser(userId)
|
||||
return processUser(appId, user)
|
||||
return processUser(user)
|
||||
}
|
||||
|
||||
exports.getGlobalUsers = async (appId = null, users = null) => {
|
||||
exports.getGlobalUsers = async (users = null) => {
|
||||
const appId = getAppId()
|
||||
const db = getGlobalDB()
|
||||
let globalUsers
|
||||
if (users) {
|
||||
|
@ -86,11 +89,11 @@ exports.getGlobalUsers = async (appId = null, users = null) => {
|
|||
if (!appId) {
|
||||
return globalUsers
|
||||
}
|
||||
return globalUsers.map(user => exports.updateAppRole(appId, user))
|
||||
return globalUsers.map(user => exports.updateAppRole(user))
|
||||
}
|
||||
|
||||
exports.getGlobalUsersFromMetadata = async (appId, users) => {
|
||||
const globalUsers = await exports.getGlobalUsers(appId, users)
|
||||
exports.getGlobalUsersFromMetadata = async users => {
|
||||
const globalUsers = await exports.getGlobalUsers(users)
|
||||
return users.map(user => {
|
||||
const globalUser = globalUsers.find(
|
||||
globalUser => globalUser && user._id.includes(globalUser._id)
|
||||
|
|
|
@ -10,7 +10,7 @@ const {
|
|||
getDeployedAppID,
|
||||
dbExists,
|
||||
} = require("@budibase/backend-core/db")
|
||||
const CouchDB = require("../../db")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
|
||||
const BASE_AUTO_ID = 1
|
||||
|
||||
|
@ -263,14 +263,13 @@ exports.outputProcessing = async (
|
|||
rows,
|
||||
opts = { squash: true }
|
||||
) => {
|
||||
const appId = ctx.appId
|
||||
let wasArray = true
|
||||
if (!(rows instanceof Array)) {
|
||||
rows = [rows]
|
||||
wasArray = false
|
||||
}
|
||||
// attach any linked row information
|
||||
let enriched = await linkRows.attachFullLinkedDocs(ctx, table, rows)
|
||||
let enriched = await linkRows.attachFullLinkedDocs(table, rows)
|
||||
|
||||
// process formulas
|
||||
enriched = processFormulas(table, enriched)
|
||||
|
@ -289,29 +288,25 @@ exports.outputProcessing = async (
|
|||
}
|
||||
}
|
||||
if (opts.squash) {
|
||||
enriched = await linkRows.squashLinksToPrimaryDisplay(
|
||||
appId,
|
||||
table,
|
||||
enriched
|
||||
)
|
||||
enriched = await linkRows.squashLinksToPrimaryDisplay(table, enriched)
|
||||
}
|
||||
return wasArray ? enriched : enriched[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up any attachments that were attached to a row.
|
||||
* @param {string} appId The ID of the app from which a row is being deleted.
|
||||
* @param {object} table The table from which a row is being removed.
|
||||
* @param {any} row optional - the row being removed.
|
||||
* @param {any} rows optional - if multiple rows being deleted can do this in bulk.
|
||||
* @param {any} oldRow optional - if updating a row this will determine the difference.
|
||||
* @return {Promise<void>} When all attachments have been removed this will return.
|
||||
*/
|
||||
exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
|
||||
exports.cleanupAttachments = async (table, { row, rows, oldRow }) => {
|
||||
const appId = getAppId()
|
||||
if (!isProdAppID(appId)) {
|
||||
const prodAppId = getDeployedAppID(appId)
|
||||
// if prod exists, then don't allow deleting
|
||||
const exists = await dbExists(CouchDB, prodAppId)
|
||||
const exists = await dbExists(prodAppId)
|
||||
if (exists) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const CouchDB = require("../db")
|
||||
const { InternalTables } = require("../db/utils")
|
||||
const { getGlobalUser } = require("../utilities/global")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
exports.getFullUser = async (ctx, userId) => {
|
||||
const global = await getGlobalUser(ctx.appId, userId)
|
||||
const global = await getGlobalUser(userId)
|
||||
let metadata
|
||||
try {
|
||||
// this will throw an error if the db doesn't exist, or there is no appId
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const db = getAppDB()
|
||||
metadata = await db.get(userId)
|
||||
} catch (err) {
|
||||
// it is fine if there is no user metadata, just remove global db info
|
||||
|
|
|
@ -70,7 +70,7 @@ exports.getGlobalSelf = async (ctx, appId = null) => {
|
|||
}
|
||||
let json = await response.json()
|
||||
if (appId) {
|
||||
json = updateAppRole(appId, json)
|
||||
json = updateAppRole(json)
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ const {
|
|||
upload,
|
||||
ObjectStoreBuckets,
|
||||
} = require("@budibase/backend-core/objectStore")
|
||||
const CouchDB = require("../../../db")
|
||||
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
|
||||
const env = require("../../../environment")
|
||||
const { googleCallbackUrl, oidcCallbackUrl } = require("./auth")
|
||||
|
@ -252,7 +251,7 @@ exports.configChecklist = async function (ctx) {
|
|||
// TODO: Watch get started video
|
||||
|
||||
// Apps exist
|
||||
const apps = await getAllApps(CouchDB, { idsOnly: true })
|
||||
const apps = await getAllApps({ idsOnly: true })
|
||||
|
||||
// They have set up SMTP
|
||||
const smtpConfig = await getScopedFullConfig(db, {
|
||||
|
|
|
@ -9,7 +9,7 @@ const CouchDB = require("../../../db")
|
|||
exports.fetch = async ctx => {
|
||||
const tenantId = ctx.user.tenantId
|
||||
// always use the dev apps as they'll be most up to date (true)
|
||||
const apps = await getAllApps(CouchDB, { tenantId, all: true })
|
||||
const apps = await getAllApps({ tenantId, all: true })
|
||||
const promises = []
|
||||
for (let app of apps) {
|
||||
// use dev app IDs
|
||||
|
|
Loading…
Reference in New Issue