Merge branch 'master' of github.com:Budibase/budibase into feature/opinionated-sql

This commit is contained in:
mike12345567 2021-06-09 11:03:01 +01:00
commit ae0dbacb31
38 changed files with 283 additions and 310 deletions

View File

@ -5,6 +5,11 @@ on:
branches: branches:
- master - master
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -18,10 +23,6 @@ jobs:
- run: yarn lint - run: yarn lint
- run: yarn bootstrap - run: yarn bootstrap
- run: yarn build - run: yarn build
env:
POSTHOG_TOKEN: ${{ secrets.POSTHOG_TOKEN }}
POSTHOG_URL: ${{ secrets.POSTHOG_URL }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
- run: yarn test - run: yarn test
- name: Configure AWS Credentials - name: Configure AWS Credentials

View File

@ -6,6 +6,7 @@ services:
app-service: app-service:
restart: always restart: always
image: budibase/apps image: budibase/apps
container_name: bbapps
ports: ports:
- "${APP_PORT}:4002" - "${APP_PORT}:4002"
environment: environment:
@ -32,6 +33,7 @@ services:
worker-service: worker-service:
restart: always restart: always
image: budibase/worker image: budibase/worker
container_name: bbworker
ports: ports:
- "${WORKER_PORT}:4003" - "${WORKER_PORT}:4003"
environment: environment:
@ -118,7 +120,7 @@ services:
image: containrrr/watchtower image: containrrr/watchtower
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
command: --debug --http-api-update budibase/apps budibase/worker command: --debug --http-api-update bbapps bbworker
environment: environment:
- WATCHTOWER_HTTP_API=true - WATCHTOWER_HTTP_API=true
- WATCHTOWER_HTTP_API_TOKEN=budibase - WATCHTOWER_HTTP_API_TOKEN=budibase

View File

@ -1,5 +1,5 @@
{ {
"version": "0.9.30", "version": "0.9.34",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/auth", "name": "@budibase/auth",
"version": "0.9.30", "version": "0.9.34",
"description": "Authentication middlewares for budibase builder and apps", "description": "Authentication middlewares for budibase builder and apps",
"main": "src/index.js", "main": "src/index.js",
"author": "Budibase", "author": "Budibase",

View File

@ -169,7 +169,8 @@ exports.getAllApps = async ({ CouchDB, dev, all } = {}) => {
dbName.startsWith(exports.APP_PREFIX) dbName.startsWith(exports.APP_PREFIX)
) )
const appPromises = appDbNames.map(db => const appPromises = appDbNames.map(db =>
new CouchDB(db).get(DocumentTypes.APP_METADATA) // skip setup otherwise databases could be re-created
new CouchDB(db, { skip_setup: true }).get(DocumentTypes.APP_METADATA)
) )
if (appPromises.length === 0) { if (appPromises.length === 0) {
return [] return []
@ -194,6 +195,21 @@ exports.getAllApps = async ({ CouchDB, dev, all } = {}) => {
} }
} }
exports.dbExists = async (CouchDB, dbName) => {
let exists = false
try {
const db = CouchDB(dbName, { skip_setup: true })
// check if database exists
const info = await db.info()
if (info && !info.error) {
exists = true
}
} catch (err) {
exists = false
}
return exists
}
/** /**
* Generates a new configuration ID. * Generates a new configuration ID.
* @returns {string} The new configuration ID which the config doc can be stored under. * @returns {string} The new configuration ID which the config doc can be stored under.

View File

@ -20,16 +20,10 @@ async function authenticate(token, tokenSecret, profile, done) {
// use the google profile id // use the google profile id
dbUser = await db.get(userId) dbUser = await db.get(userId)
} catch (err) { } catch (err) {
console.log("Google user not found. Creating..")
// create the user
const user = { const user = {
_id: userId, _id: userId,
provider: profile.provider, provider: profile.provider,
roles: {}, roles: {},
builder: {
global: true,
},
...profile._json, ...profile._json,
} }
@ -50,12 +44,18 @@ async function authenticate(token, tokenSecret, profile, done) {
user.roles = existing.roles user.roles = existing.roles
user.builder = existing.builder user.builder = existing.builder
user.admin = existing.admin user.admin = existing.admin
}
const response = await db.post(user) const response = await db.post(user)
dbUser = user dbUser = user
dbUser._rev = response.rev dbUser._rev = response.rev
} else {
return done(
new Error(
"email does not yet exist. You must set up your local budibase account first."
),
false
)
}
} }
// authenticate // authenticate

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/bbui", "name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.", "description": "A UI solution used in the different Budibase projects.",
"version": "0.9.30", "version": "0.9.34",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"module": "dist/bbui.es.js", "module": "dist/bbui.es.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "0.9.30", "version": "0.9.34",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -65,10 +65,10 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^0.9.30", "@budibase/bbui": "^0.9.34",
"@budibase/client": "^0.9.30", "@budibase/client": "^0.9.34",
"@budibase/colorpicker": "1.1.2", "@budibase/colorpicker": "1.1.2",
"@budibase/string-templates": "^0.9.30", "@budibase/string-templates": "^0.9.34",
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1", "@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1", "@spectrum-css/vars": "^3.0.1",

View File

@ -1,5 +1,5 @@
<script> <script>
import { store, allScreens } from "builderStore" import { store, allScreens, selectedAccessRole } from "builderStore"
import { tables } from "stores/backend" import { tables } from "stores/backend"
import { roles } from "stores/backend" import { roles } from "stores/backend"
import { Input, Select, ModalContent, Toggle } from "@budibase/bbui" import { Input, Select, ModalContent, Toggle } from "@budibase/bbui"
@ -14,7 +14,7 @@
let templateIndex let templateIndex
let draftScreen let draftScreen
let createLink = true let createLink = true
let roleId = "BASIC" let roleId = $selectedAccessRole || "BASIC"
$: templates = getTemplates($store, $tables.list) $: templates = getTemplates($store, $tables.list)
$: route = !route && $allScreens.length === 0 ? "*" : route $: route = !route && $allScreens.length === 0 ? "*" : route

View File

@ -48,6 +48,8 @@
$: integrationInfo = $integrations[datasourceType] $: integrationInfo = $integrations[datasourceType]
$: queryConfig = integrationInfo?.query $: queryConfig = integrationInfo?.query
$: shouldShowQueryConfig = queryConfig && query.queryVerb $: shouldShowQueryConfig = queryConfig && query.queryVerb
$: readQuery = query.queryVerb === "read" || query.readable
$: queryInvalid = !query.name || (readQuery && data.length === 0)
function newField() { function newField() {
fields = [...fields, {}] fields = [...fields, {}]
@ -150,11 +152,7 @@
<div class="viewer-controls"> <div class="viewer-controls">
<Heading size="S">Results</Heading> <Heading size="S">Results</Heading>
<ButtonGroup> <ButtonGroup>
<Button <Button cta disabled={queryInvalid} on:click={saveQuery}>
cta
disabled={data.length === 0 || !query.name}
on:click={saveQuery}
>
Save Query Save Query
</Button> </Button>
<Button secondary on:click={previewQuery}>Run Query</Button> <Button secondary on:click={previewQuery}>Run Query</Button>

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "0.9.30", "version": "0.9.34",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js", "main": "src/index.js",
"bin": { "bin": {
@ -25,7 +25,7 @@
"inquirer": "^8.0.0", "inquirer": "^8.0.0",
"lookpath": "^1.1.0", "lookpath": "^1.1.0",
"pkg": "^4.4.9", "pkg": "^4.4.9",
"posthog-node": "^1.0.7", "posthog-node": "1.0.7",
"randomstring": "^1.1.5" "randomstring": "^1.1.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1223,7 +1223,7 @@ pkg@^4.4.9:
resolve "^1.15.1" resolve "^1.15.1"
stream-meter "^1.0.4" stream-meter "^1.0.4"
posthog-node@^1.0.7: posthog-node@1.0.7:
version "1.0.7" version "1.0.7"
resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-1.0.7.tgz#a7a9525eebff23312117e57cff3ddac82afb2262" resolved "https://registry.yarnpkg.com/posthog-node/-/posthog-node-1.0.7.tgz#a7a9525eebff23312117e57cff3ddac82afb2262"
integrity sha512-KTCwyU+PU1eAQtjy5ZSJ47mrxv2d/mMkxo+vvV5c+YqfE4mBAY1UPEPMv1nElb5Vq0UnxvyQXaUnOn8d8Xr6Eg== integrity sha512-KTCwyU+PU1eAQtjy5ZSJ47mrxv2d/mMkxo+vvV5c+YqfE4mBAY1UPEPMv1nElb5Vq0UnxvyQXaUnOn8d8Xr6Eg==

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "0.9.30", "version": "0.9.34",
"license": "MPL-2.0", "license": "MPL-2.0",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
@ -18,13 +18,13 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/string-templates": "^0.9.30", "@budibase/string-templates": "^0.9.34",
"regexparam": "^1.3.0", "regexparam": "^1.3.0",
"shortid": "^2.2.15", "shortid": "^2.2.15",
"svelte-spa-router": "^3.0.5" "svelte-spa-router": "^3.0.5"
}, },
"devDependencies": { "devDependencies": {
"@budibase/standard-components": "^0.9.30", "@budibase/standard-components": "^0.9.34",
"@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1", "@rollup/plugin-node-resolve": "^11.2.1",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",

View File

@ -3,9 +3,9 @@ import API from "./api"
/** /**
* Uploads an attachment to the server. * Uploads an attachment to the server.
*/ */
export const uploadAttachment = async data => { export const uploadAttachment = async (data, tableId = "") => {
return await API.post({ return await API.post({
url: "/api/attachments/upload", url: `/api/attachments/${tableId}/upload`,
body: data, body: data,
json: false, json: false,
}) })

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "0.9.30", "version": "0.9.34",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/electron.js", "main": "src/electron.js",
"repository": { "repository": {
@ -55,9 +55,9 @@
"author": "Budibase", "author": "Budibase",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@budibase/auth": "^0.9.30", "@budibase/auth": "^0.9.34",
"@budibase/client": "^0.9.30", "@budibase/client": "^0.9.34",
"@budibase/string-templates": "^0.9.30", "@budibase/string-templates": "^0.9.34",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",
"@koa/router": "8.0.0", "@koa/router": "8.0.0",
"@sendgrid/mail": "7.1.1", "@sendgrid/mail": "7.1.1",
@ -110,7 +110,7 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.3", "@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.4", "@babel/preset-env": "^7.14.4",
"@budibase/standard-components": "^0.9.30", "@budibase/standard-components": "^0.9.34",
"@jest/test-sequencer": "^24.8.0", "@jest/test-sequencer": "^24.8.0",
"babel-jest": "^27.0.2", "babel-jest": "^27.0.2",
"docker-compose": "^0.23.6", "docker-compose": "^0.23.6",

View File

@ -5,6 +5,10 @@ const { join } = require("path")
const CouchDB = require("../src/db") const CouchDB = require("../src/db")
// load environment // load environment
const env = require("../src/environment") const env = require("../src/environment")
const {
USER_METDATA_PREFIX,
LINK_USER_METADATA_PREFIX,
} = require("../src/db/utils")
// Script to export a chosen budibase app into a package // Script to export a chosen budibase app into a package
// Usage: ./scripts/exportAppTemplate.js export --name=Funky --appId=appId // Usage: ./scripts/exportAppTemplate.js export --name=Funky --appId=appId
@ -44,7 +48,13 @@ yargs
// perform couch dump // perform couch dump
const instanceDb = new CouchDB(appId) const instanceDb = new CouchDB(appId)
await instanceDb.dump(writeStream, {}) await instanceDb.dump(writeStream, {
filter: doc =>
!(
doc._id.includes(USER_METDATA_PREFIX) ||
doc.includes(LINK_USER_METADATA_PREFIX)
),
})
console.log(`Template ${name} exported to ${exportPath}`) console.log(`Template ${name} exported to ${exportPath}`)
} }
) )

View File

@ -99,18 +99,11 @@ async function createInstance(template) {
// replicate the template data to the instance DB // replicate the template data to the instance DB
// this is currently very hard to test, downloading and importing template files // this is currently very hard to test, downloading and importing template files
/* istanbul ignore next */ /* istanbul ignore next */
let _rev
if (template && template.useTemplate === "true") { if (template && template.useTemplate === "true") {
const { ok } = await db.load(await getTemplateStream(template)) const { ok } = await db.load(await getTemplateStream(template))
if (!ok) { if (!ok) {
throw "Error loading database dump from template." throw "Error loading database dump from template."
} }
try {
const response = await db.get(DocumentTypes.APP_METADATA)
_rev = response._rev
} catch (err) {
_rev = null
}
} else { } else {
// create the users table // create the users table
await db.put(USERS_TABLE_SCHEMA) await db.put(USERS_TABLE_SCHEMA)
@ -121,7 +114,7 @@ async function createInstance(template) {
await createRoutingView(appId) await createRoutingView(appId)
await createAllSearchIndex(appId) await createAllSearchIndex(appId)
return { _id: appId, _rev } return { _id: appId }
} }
exports.fetch = async function (ctx) { exports.fetch = async function (ctx) {
@ -188,11 +181,21 @@ exports.create = async function (ctx) {
instanceConfig.file = ctx.request.files.templateFile instanceConfig.file = ctx.request.files.templateFile
} }
const instance = await createInstance(instanceConfig) const instance = await createInstance(instanceConfig)
const appId = instance._id
const url = await getAppUrlIfNotInUse(ctx) const url = await getAppUrlIfNotInUse(ctx)
const appId = instance._id const db = new CouchDB(appId)
let _rev
try {
// if template there will be an existing doc
const existing = await db.get(DocumentTypes.APP_METADATA)
_rev = existing._rev
} catch (err) {
// nothing to do
}
const newApplication = { const newApplication = {
_id: DocumentTypes.APP_METADATA, _id: DocumentTypes.APP_METADATA,
_rev,
appId: instance._id, appId: instance._id,
type: "app", type: "app",
version: packageJson.version, version: packageJson.version,
@ -204,11 +207,7 @@ exports.create = async function (ctx) {
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
} }
if (instance._rev) { await db.put(newApplication, { force: true })
newApplication._rev = instance._rev
}
const instanceDb = new CouchDB(appId)
await instanceDb.put(newApplication)
await createEmptyAppPackage(ctx, newApplication) await createEmptyAppPackage(ctx, newApplication)
/* istanbul ignore next */ /* istanbul ignore next */

View File

@ -60,7 +60,7 @@ exports.save = async function (ctx) {
ctx.message = `Query ${query.name} saved successfully.` ctx.message = `Query ${query.name} saved successfully.`
} }
async function enrichQueryFields(fields, parameters) { async function enrichQueryFields(fields, parameters = {}) {
const enrichedQuery = {} const enrichedQuery = {}
// enrich the fields with dynamic parameters // enrich the fields with dynamic parameters

View File

@ -4,10 +4,8 @@ const {
getUserMetadataParams, getUserMetadataParams,
} = require("../../db/utils") } = require("../../db/utils")
const { InternalTables } = require("../../db/utils") const { InternalTables } = require("../../db/utils")
const { const { addAppRoleToUser } = require("../../utilities/workerRequests")
getGlobalUsers, const { getGlobalUsers } = require("../../utilities/global")
addAppRoleToUser,
} = require("../../utilities/workerRequests")
const { getFullUser } = require("../../utilities/users") const { getFullUser } = require("../../utilities/users")
function removeGlobalProps(user) { function removeGlobalProps(user) {
@ -20,7 +18,7 @@ function removeGlobalProps(user) {
exports.fetchMetadata = async function (ctx) { exports.fetchMetadata = async function (ctx) {
const database = new CouchDB(ctx.appId) const database = new CouchDB(ctx.appId)
const global = await getGlobalUsers(ctx, ctx.appId) const global = await getGlobalUsers(ctx.appId)
const metadata = ( const metadata = (
await database.allDocs( await database.allDocs(
getUserMetadataParams(null, { getUserMetadataParams(null, {

View File

@ -7,8 +7,8 @@ const {
PermissionTypes, PermissionTypes,
PermissionLevels, PermissionLevels,
} = require("@budibase/auth/permissions") } = require("@budibase/auth/permissions")
const usage = require("../../middleware/usageQuota")
const env = require("../../environment") const env = require("../../environment")
const { paramResource } = require("../../middleware/resourceId")
const router = Router() const router = Router()
@ -39,9 +39,9 @@ router
.get("/builder/:file*", controller.serveBuilder) .get("/builder/:file*", controller.serveBuilder)
.post("/api/attachments/process", authorized(BUILDER), controller.uploadFile) .post("/api/attachments/process", authorized(BUILDER), controller.uploadFile)
.post( .post(
"/api/attachments/upload", "/api/attachments/:tableId/upload",
paramResource("tableId"),
authorized(PermissionTypes.TABLE, PermissionLevels.WRITE), authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
usage,
controller.uploadFile controller.uploadFile
) )
.get("/componentlibrary", controller.serveComponentLibrary) .get("/componentlibrary", controller.serveComponentLibrary)

View File

@ -26,11 +26,6 @@ describe("/routing", () => {
describe("fetch", () => { describe("fetch", () => {
it("returns the correct routing for basic user", async () => { it("returns the correct routing for basic user", async () => {
workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => {
return {
roleId: BUILTIN_ROLE_IDS.BASIC,
}
})
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders({ .set(await config.roleHeaders({
@ -52,13 +47,6 @@ describe("/routing", () => {
}) })
it("returns the correct routing for power user", async () => { it("returns the correct routing for power user", async () => {
workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => {
return {
roles: {
[appId]: BUILTIN_ROLE_IDS.POWER,
}
}
})
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders({ .set(await config.roleHeaders({

View File

@ -1,7 +1,6 @@
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions")
const setup = require("./utilities") const setup = require("./utilities")
const workerRequests = require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({ jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(() => { getGlobalUsers: jest.fn(() => {
@ -25,30 +24,18 @@ describe("/users", () => {
}) })
describe("fetch", () => { describe("fetch", () => {
beforeEach(() => {
workerRequests.getGlobalUsers.mockImplementationOnce(() => ([
{
_id: "us_uuid1",
},
{
_id: "us_uuid2",
}
]
))
})
it("returns a list of users from an instance db", async () => { it("returns a list of users from an instance db", async () => {
await config.createUser("brenda@brenda.com", "brendas_password") await config.createUser("uuidx")
await config.createUser("pam@pam.com", "pam_password") await config.createUser("uuidy")
const res = await request const res = await request
.get(`/api/users/metadata`) .get(`/api/users/metadata`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
expect(res.body.length).toBe(2) expect(res.body.length).toBe(3)
expect(res.body.find(u => u._id === `ro_ta_users_us_uuid1`)).toBeDefined() expect(res.body.find(u => u._id === `ro_ta_users_us_uuidx`)).toBeDefined()
expect(res.body.find(u => u._id === `ro_ta_users_us_uuid2`)).toBeDefined() expect(res.body.find(u => u._id === `ro_ta_users_us_uuidy`)).toBeDefined()
}) })
it("should apply authorization to endpoint", async () => { it("should apply authorization to endpoint", async () => {
@ -65,9 +52,6 @@ describe("/users", () => {
}) })
describe("update", () => { describe("update", () => {
beforeEach(() => {
})
it("should be able to update the user", async () => { it("should be able to update the user", async () => {
const user = await config.createUser() const user = await config.createUser()
user.roleId = BUILTIN_ROLE_IDS.BASIC user.roleId = BUILTIN_ROLE_IDS.BASIC
@ -94,14 +78,6 @@ describe("/users", () => {
}) })
describe("find", () => { describe("find", () => {
beforeEach(() => {
jest.resetAllMocks()
workerRequests.getGlobalUsers.mockImplementationOnce(() => ({
_id: "us_uuid1",
roleId: BUILTIN_ROLE_IDS.POWER,
}))
})
it("should be able to find the user", async () => { it("should be able to find the user", async () => {
const user = await config.createUser() const user = await config.createUser()
const res = await request const res = await request
@ -110,7 +86,7 @@ describe("/users", () => {
.expect(200) .expect(200)
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
expect(res.body._id).toEqual(user._id) expect(res.body._id).toEqual(user._id)
expect(res.body.roleId).toEqual(BUILTIN_ROLE_IDS.POWER) expect(res.body.roleId).toEqual(BUILTIN_ROLE_IDS.ADMIN)
expect(res.body.tableId).toBeDefined() expect(res.body.tableId).toBeDefined()
}) })
}) })

View File

@ -11,7 +11,9 @@ const {
const { flatten } = require("lodash") const { flatten } = require("lodash")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const { FieldTypes } = require("../../constants") const { FieldTypes } = require("../../constants")
const { getMultiIDParams } = require("../../db/utils") const { getMultiIDParams, USER_METDATA_PREFIX } = require("../../db/utils")
const { partition } = require("lodash")
const { getGlobalUsers } = require("../../utilities/global")
/** /**
* This functionality makes sure that when rows with links are created, updated or deleted they are processed * This functionality makes sure that when rows with links are created, updated or deleted they are processed
@ -57,6 +59,31 @@ async function getLinksForRows(appId, rows) {
) )
} }
async function getFullLinkedDocs(appId, links) {
// create DBs
const db = new CouchDB(appId)
const linkedRowIds = links.map(link => link.id)
let linked = (await db.allDocs(getMultiIDParams(linkedRowIds))).rows.map(
row => row.doc
)
// need to handle users as specific cases
let [users, other] = partition(linked, linkRow =>
linkRow._id.startsWith(USER_METDATA_PREFIX)
)
const globalUsers = await getGlobalUsers(appId, users)
users = users.map(user => {
const globalUser = globalUsers.find(
globalUser => globalUser && user._id.includes(globalUser._id)
)
return {
...globalUser,
// doing user second overwrites the id and rev (always metadata)
...user,
}
})
return [...other, ...users]
}
/** /**
* Update link documents for a row or table - this is to be called by the API controller when a change is occurring. * Update link documents for a row or table - this is to be called by the API controller when a change is occurring.
* @param {string} eventType states what type of change which is occurring, means this can be expanded upon in the * @param {string} eventType states what type of change which is occurring, means this can be expanded upon in the
@ -154,14 +181,13 @@ exports.attachFullLinkedDocs = async (appId, table, rows) => {
if (linkedTableIds.length === 0) { if (linkedTableIds.length === 0) {
return rows return rows
} }
// create DBs
const db = new CouchDB(appId) const db = new CouchDB(appId)
// get all the links
const links = (await getLinksForRows(appId, rows)).filter(link => const links = (await getLinksForRows(appId, rows)).filter(link =>
rows.some(row => row._id === link.thisId) rows.some(row => row._id === link.thisId)
) )
const linkedRowIds = links.map(link => link.id) let linked = await getFullLinkedDocs(appId, links)
const linked = (await db.allDocs(getMultiIDParams(linkedRowIds))).rows.map(
row => row.doc
)
const linkedTables = [] const linkedTables = []
for (let row of rows) { for (let row of rows) {
for (let link of links.filter(link => link.thisId === row._id)) { for (let link of links.filter(link => link.thisId === row._id)) {

View File

@ -6,17 +6,11 @@ const {
APP_DEV_PREFIX, APP_DEV_PREFIX,
APP_PREFIX, APP_PREFIX,
SEPARATOR, SEPARATOR,
StaticDatabases,
} = require("@budibase/auth/db") } = require("@budibase/auth/db")
const UNICODE_MAX = "\ufff0" const UNICODE_MAX = "\ufff0"
const StaticDatabases = {
BUILDER: {
name: "builder-db",
baseDoc: "builder-doc",
},
}
const AppStatus = { const AppStatus = {
DEV: "development", DEV: "development",
ALL: "all", ALL: "all",
@ -55,9 +49,18 @@ const SearchIndexes = {
ROWS: "rows", ROWS: "rows",
} }
exports.StaticDatabases = {
BUILDER: {
name: "builder-db",
baseDoc: "builder-doc",
},
...StaticDatabases,
}
exports.APP_PREFIX = APP_PREFIX exports.APP_PREFIX = APP_PREFIX
exports.APP_DEV_PREFIX = APP_DEV_PREFIX exports.APP_DEV_PREFIX = APP_DEV_PREFIX
exports.StaticDatabases = StaticDatabases exports.USER_METDATA_PREFIX = `${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
exports.LINK_USER_METADATA_PREFIX = `${DocumentTypes.LINK}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
exports.ViewNames = ViewNames exports.ViewNames = ViewNames
exports.InternalTables = InternalTables exports.InternalTables = InternalTables
exports.DocumentTypes = DocumentTypes exports.DocumentTypes = DocumentTypes

View File

@ -1,9 +1,16 @@
const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils const {
getAppId,
setCookie,
getCookie,
clearCookie,
} = require("@budibase/auth").utils
const { Cookies } = require("@budibase/auth").constants const { Cookies } = require("@budibase/auth").constants
const { getRole } = require("@budibase/auth/roles") const { getRole } = require("@budibase/auth/roles")
const { getGlobalSelf } = require("../utilities/workerRequests") const { getGlobalSelf } = require("../utilities/workerRequests")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { generateUserMetadataID } = require("../db/utils") const { generateUserMetadataID } = require("../db/utils")
const { dbExists } = require("@budibase/auth/db")
const CouchDB = require("../db")
module.exports = async (ctx, next) => { module.exports = async (ctx, next) => {
// try to get the appID from the request // try to get the appID from the request
@ -13,6 +20,15 @@ module.exports = async (ctx, next) => {
if (!appCookie && !requestAppId) { if (!appCookie && !requestAppId) {
return next() return next()
} }
// check the app exists referenced in cookie
if (appCookie) {
const appId = appCookie.appId
const exists = await dbExists(CouchDB, appId)
if (!exists) {
clearCookie(ctx, Cookies.CurrentApp)
return next()
}
}
let updateCookie = false, let updateCookie = false,
appId, appId,

View File

@ -306,8 +306,8 @@ class TestConfiguration {
return await this._req(config, null, controllers.layout.save) return await this._req(config, null, controllers.layout.save)
} }
async createUser() { async createUser(id = null) {
const globalId = `us_${Math.random()}` const globalId = !id ? `us_${Math.random()}` : `us_${id}`
const resp = await this.globalUser(globalId) const resp = await this.globalUser(globalId)
return { return {
...resp, ...resp,

View File

@ -18,6 +18,10 @@ const download = require("download")
const env = require("../../environment") const env = require("../../environment")
const { homedir } = require("os") const { homedir } = require("os")
const fetch = require("node-fetch") const fetch = require("node-fetch")
const {
USER_METDATA_PREFIX,
LINK_USER_METADATA_PREFIX,
} = require("../../db/utils")
const DEFAULT_AUTOMATION_BUCKET = const DEFAULT_AUTOMATION_BUCKET =
"https://prod-budi-automations.s3-eu-west-1.amazonaws.com" "https://prod-budi-automations.s3-eu-west-1.amazonaws.com"
@ -117,7 +121,14 @@ exports.performBackup = async (appId, backupName) => {
const writeStream = fs.createWriteStream(path) const writeStream = fs.createWriteStream(path)
// perform couch dump // perform couch dump
const instanceDb = new CouchDB(appId) const instanceDb = new CouchDB(appId)
await instanceDb.dump(writeStream, {}) await instanceDb.dump(writeStream, {
// filter out anything that has a user metadata structure in its ID
filter: doc =>
!(
doc._id.includes(USER_METDATA_PREFIX) ||
doc.includes(LINK_USER_METADATA_PREFIX)
),
})
// write the file to the object store // write the file to the object store
await streamUpload( await streamUpload(
ObjectStoreBuckets.BACKUPS, ObjectStoreBuckets.BACKUPS,

View File

@ -0,0 +1,64 @@
const CouchDB = require("../db")
const {
getMultiIDParams,
getGlobalIDFromUserMetadataID,
StaticDatabases,
} = require("../db/utils")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getDeployedAppID } = require("@budibase/auth/db")
const { getGlobalUserParams } = require("@budibase/auth/db")
exports.updateAppRole = (appId, user) => {
if (!user.roles) {
return user
}
if (user.builder && user.builder.global) {
user.roleId = BUILTIN_ROLE_IDS.ADMIN
} else {
// always use the deployed app
user.roleId = user.roles[getDeployedAppID(appId)]
if (!user.roleId) {
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
}
}
delete user.roles
return user
}
exports.getGlobalUser = async (appId, userId) => {
const db = CouchDB(StaticDatabases.GLOBAL.name)
let user = await db.get(getGlobalIDFromUserMetadataID(userId))
if (user) {
delete user.password
}
return exports.updateAppRole(appId, user)
}
exports.getGlobalUsers = async (appId = null, users = null) => {
const db = CouchDB(StaticDatabases.GLOBAL.name)
let globalUsers
if (users) {
const globalIds = users.map(user => getGlobalIDFromUserMetadataID(user._id))
globalUsers = (await db.allDocs(getMultiIDParams(globalIds))).rows.map(
row => row.doc
)
} else {
globalUsers = (
await db.allDocs(
getGlobalUserParams(null, {
include_docs: true,
})
)
).rows.map(row => row.doc)
}
globalUsers = globalUsers
.filter(user => user != null)
.map(user => {
delete user.password
return user
})
if (!appId) {
return globalUsers
}
return globalUsers.map(user => exports.updateAppRole(appId, user))
}

View File

@ -1,13 +1,9 @@
const CouchDB = require("../db") const CouchDB = require("../db")
const { getGlobalIDFromUserMetadataID, InternalTables } = require("../db/utils") const { InternalTables } = require("../db/utils")
const { getGlobalUsers } = require("../utilities/workerRequests") const { getGlobalUser } = require("../utilities/global")
exports.getFullUser = async (ctx, userId) => { exports.getFullUser = async (ctx, userId) => {
const global = await getGlobalUsers( const global = await getGlobalUser(ctx.appId, userId)
ctx,
ctx.appId,
getGlobalIDFromUserMetadataID(userId)
)
let metadata let metadata
try { try {
// this will throw an error if the db doesn't exist, or there is no appId // this will throw an error if the db doesn't exist, or there is no appId

View File

@ -1,26 +1,8 @@
const fetch = require("node-fetch") const fetch = require("node-fetch")
const env = require("../environment") const env = require("../environment")
const { checkSlashesInUrl } = require("./index") const { checkSlashesInUrl } = require("./index")
const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
const { getDeployedAppID } = require("@budibase/auth/db") const { getDeployedAppID } = require("@budibase/auth/db")
const { getGlobalIDFromUserMetadataID } = require("../db/utils") const { updateAppRole, getGlobalUser } = require("./global")
function getAppRole(appId, user) {
if (!user.roles) {
return user
}
if (user.builder && user.builder.global) {
user.roleId = BUILTIN_ROLE_IDS.ADMIN
} else {
// always use the deployed app
user.roleId = user.roles[getDeployedAppID(appId)]
if (!user.roleId) {
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
}
}
delete user.roles
return user
}
function request(ctx, request, noApiKey) { function request(ctx, request, noApiKey) {
if (!request.headers) { if (!request.headers) {
@ -90,27 +72,6 @@ exports.getDeployedApps = async ctx => {
} }
} }
exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
const endpoint = globalId
? `/api/admin/users/${globalId}`
: `/api/admin/users`
const reqCfg = { method: "GET" }
const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + endpoint),
request(ctx, reqCfg)
)
let users = await response.json()
if (!appId) {
return users
}
if (Array.isArray(users)) {
users = users.map(user => getAppRole(appId, user))
} else {
users = getAppRole(appId, users)
}
return users
}
exports.getGlobalSelf = async (ctx, appId = null) => { exports.getGlobalSelf = async (ctx, appId = null) => {
const endpoint = `/api/admin/users/self` const endpoint = `/api/admin/users/self`
const response = await fetch( const response = await fetch(
@ -123,7 +84,7 @@ exports.getGlobalSelf = async (ctx, appId = null) => {
} }
let json = await response.json() let json = await response.json()
if (appId) { if (appId) {
json = getAppRole(appId, json) json = updateAppRole(appId, json)
} }
return json return json
} }
@ -136,8 +97,7 @@ exports.addAppRoleToUser = async (ctx, appId, roleId, userId = null) => {
user = await exports.getGlobalSelf(ctx) user = await exports.getGlobalSelf(ctx)
endpoint = `/api/admin/users/self` endpoint = `/api/admin/users/self`
} else { } else {
userId = getGlobalIDFromUserMetadataID(userId) user = await getGlobalUser(appId, userId)
user = await exports.getGlobalUsers(ctx, appId, userId)
body._id = userId body._id = userId
endpoint = `/api/admin/users` endpoint = `/api/admin/users`
} }

View File

@ -1057,10 +1057,10 @@
"@babel/helper-validator-identifier" "^7.14.0" "@babel/helper-validator-identifier" "^7.14.0"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
"@budibase/auth@^0.9.24": "@budibase/auth@^0.9.34":
version "0.9.24" version "0.9.34"
resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.24.tgz#7c8e02076025d97734a5815a7c17562a566c23c2" resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.34.tgz#f617cedf7d53465b431f399655beb23611b01027"
integrity sha512-uYYw29mOtzeQ16uBaOmcT+OabGhXxeTcXFexayZDv4s9d6F3wpvxi/t7MMemCmUP0cSxuFd9DOiJj58iMLILDA== integrity sha512-na5W3dVqV9/d7/nINRikYFqPQwUhU7tZG/pRc+zJgFbqzZOB/bDdKiPszffelPENxLSu+ACT+xLES3YbtThPWg==
dependencies: dependencies:
aws-sdk "^2.901.0" aws-sdk "^2.901.0"
bcryptjs "^2.4.3" bcryptjs "^2.4.3"
@ -1078,10 +1078,10 @@
uuid "^8.3.2" uuid "^8.3.2"
zlib "^1.0.5" zlib "^1.0.5"
"@budibase/bbui@^0.9.24": "@budibase/bbui@^0.9.34":
version "0.9.24" version "0.9.34"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.24.tgz#ee0c2b5cbbf478492b525ef365c09311b0a59a70" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.34.tgz#44c0a0e7b6ca2c607841130063ce59b4fd5e27d9"
integrity sha512-FaZo1zk2CN/MeCarAw9qaDMO3PDIBzGTV5cZ1wHg5KDAEoTx4xLkxDdCbJOLbA42zBPUks5Mru7C9qomQUc8yQ== integrity sha512-kH74IG2/m9txaSy+n+zF6viLXX+5DDc7acbhIOWc9Ch+GzEcZlQFpF5GvL16Bi01p7U/YtqJLP2CdhbyaKt1CQ==
dependencies: dependencies:
"@adobe/spectrum-css-workflow-icons" "^1.2.1" "@adobe/spectrum-css-workflow-icons" "^1.2.1"
"@spectrum-css/actionbutton" "^1.0.1" "@spectrum-css/actionbutton" "^1.0.1"
@ -1126,12 +1126,12 @@
svelte-flatpickr "^3.1.0" svelte-flatpickr "^3.1.0"
svelte-portal "^1.0.0" svelte-portal "^1.0.0"
"@budibase/client@^0.9.24": "@budibase/client@^0.9.34":
version "0.9.24" version "0.9.34"
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.24.tgz#a6bcc641f961715c1701c4dcc03fe0fb7a8de9bd" resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.34.tgz#d01ba1d24de04ec739a7b33a6c3012448b580322"
integrity sha512-L3MIpRU0ncsFh9uPk2BcoZ1D52Of1LZNJGWxPt8QdhBvtLuKqD6sM3rdKuUA0EsUOn7hgPIZl82SEolQQz9Dyw== integrity sha512-s22VrNg6eEdY3dcrzv2BSH/edbGfMWlMPTq7gOq7bzzgLR+xDz0goLvn9J/blQIf9YsNNSDqYUZqAXObxFpB1Q==
dependencies: dependencies:
"@budibase/string-templates" "^0.9.24" "@budibase/string-templates" "^0.9.34"
regexparam "^1.3.0" regexparam "^1.3.0"
shortid "^2.2.15" shortid "^2.2.15"
svelte-spa-router "^3.0.5" svelte-spa-router "^3.0.5"
@ -1168,22 +1168,23 @@
to-gfm-code-block "^0.1.1" to-gfm-code-block "^0.1.1"
year "^0.2.1" year "^0.2.1"
"@budibase/standard-components@^0.9.24": "@budibase/standard-components@^0.9.34":
version "0.9.24" version "0.9.34"
resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.24.tgz#f14b81fea6a1b2f7d5212b523ec9097be505af89" resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.34.tgz#0da54fbff01925f1145180bf168e9577f494477a"
integrity sha512-TWdfi044EaT1NigZB02NmTARfamlN8anHjc87QZfNdbdPxD9tgLxcPe/sPaPd5ACBjVC6McL3sKJs2xCbB78Ig== integrity sha512-BMbWIxPeNkj0U/e3ItfwZLQ5BUXmlJg9QHRNRxOws8D2xjV5wpPPaXYk4wVp0S5ob/aChETVIOF2DcrZH6V+Xg==
dependencies: dependencies:
"@budibase/bbui" "^0.9.24" "@budibase/bbui" "^0.9.34"
"@spectrum-css/page" "^3.0.1" "@spectrum-css/page" "^3.0.1"
"@spectrum-css/vars" "^3.0.1" "@spectrum-css/vars" "^3.0.1"
apexcharts "^3.22.1" apexcharts "^3.22.1"
dayjs "^1.10.5"
svelte-apexcharts "^1.0.2" svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0" svelte-flatpickr "^3.1.0"
"@budibase/string-templates@^0.9.24": "@budibase/string-templates@^0.9.34":
version "0.9.24" version "0.9.34"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.24.tgz#8feea5e1510b8e615b5db2c58b7907b64ebdd8bf" resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.34.tgz#ec1a6833ef9767fcdf09203ae5ff3280974001c8"
integrity sha512-CeACQYbzsxrvjcrcbzEIRHbcJgy7siXz1ybxBxgErcKX/WhVpPKKAcviyW+5m9RnRWpD3OWOfHFZdzrVreVxjw== integrity sha512-qZqs1ECJG3pAp3QTYQx1gz0yeBW8tIKcFnVXRyvP2MuJPOClbqjEci1YWAGiZR4ddbChbAULAYBsxRYCBlwiKQ==
dependencies: dependencies:
"@budibase/handlebars-helpers" "^0.11.3" "@budibase/handlebars-helpers" "^0.11.3"
dayjs "^1.10.4" dayjs "^1.10.4"
@ -3866,7 +3867,7 @@ dateformat@^3.0.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@^1.10.4: dayjs@^1.10.4, dayjs@^1.10.5:
version "1.10.5" version "1.10.5"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.5.tgz#5600df4548fc2453b3f163ebb2abbe965ccfb986"
integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g== integrity sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==

View File

@ -29,11 +29,11 @@
"keywords": [ "keywords": [
"svelte" "svelte"
], ],
"version": "0.9.30", "version": "0.9.34",
"license": "MIT", "license": "MIT",
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc", "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc",
"dependencies": { "dependencies": {
"@budibase/bbui": "^0.9.30", "@budibase/bbui": "^0.9.34",
"@spectrum-css/page": "^3.0.1", "@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1", "@spectrum-css/vars": "^3.0.1",
"apexcharts": "^3.22.1", "apexcharts": "^3.22.1",

View File

@ -9,8 +9,10 @@
let fieldState let fieldState
let fieldApi let fieldApi
let fieldSchema
const { API, notifications } = getContext("sdk") const { API, notifications } = getContext("sdk")
const formContext = getContext("form")
const BYTES_IN_MB = 1000000 const BYTES_IN_MB = 1000000
export let files = [] export let files = []
@ -28,7 +30,7 @@
for (let i = 0; i < fileList.length; i++) { for (let i = 0; i < fileList.length; i++) {
data.append("file", fileList[i]) data.append("file", fileList[i])
} }
return await API.uploadAttachment(data) return await API.uploadAttachment(data, formContext?.dataSource?.tableId)
} }
</script> </script>
@ -45,7 +47,9 @@
<CoreDropzone <CoreDropzone
value={$fieldState.value} value={$fieldState.value}
disabled={$fieldState.disabled} disabled={$fieldState.disabled}
on:change={e => fieldApi.setValue(e.detail)} on:change={e => {
fieldApi.setValue(e.detail)
}}
{processFiles} {processFiles}
{handleFileTooLarge} {handleFileTooLarge}
/> />

View File

@ -80,7 +80,7 @@
} }
// Provide both form API and state to children // Provide both form API and state to children
setContext("form", { formApi, formState }) setContext("form", { formApi, formState, dataSource })
// Action context to pass to children // Action context to pass to children
$: actions = [{ type: ActionTypes.ValidateForm, callback: formApi.validate }] $: actions = [{ type: ActionTypes.ValidateForm, callback: formApi.validate }]

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/string-templates", "name": "@budibase/string-templates",
"version": "0.9.30", "version": "0.9.34",
"description": "Handlebars wrapper for Budibase templating.", "description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs", "main": "src/index.cjs",
"module": "dist/bundle.mjs", "module": "dist/bundle.mjs",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/worker", "name": "@budibase/worker",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "0.9.30", "version": "0.9.34",
"description": "Budibase background service", "description": "Budibase background service",
"main": "src/index.js", "main": "src/index.js",
"repository": { "repository": {
@ -21,8 +21,8 @@
"author": "Budibase", "author": "Budibase",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"@budibase/auth": "^0.9.30", "@budibase/auth": "^0.9.34",
"@budibase/string-templates": "^0.9.30", "@budibase/string-templates": "^0.9.34",
"@koa/router": "^8.0.0", "@koa/router": "^8.0.0",
"aws-sdk": "^2.811.0", "aws-sdk": "^2.811.0",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",

View File

@ -1,19 +1,12 @@
const fetch = require("node-fetch")
const { DocumentTypes } = require("@budibase/auth").db const { DocumentTypes } = require("@budibase/auth").db
const CouchDB = require("../../db") const CouchDB = require("../../db")
const env = require("../../environment")
const APP_PREFIX = "app_" const APP_PREFIX = "app_"
const URL_REGEX_SLASH = /\/|\\/g const URL_REGEX_SLASH = /\/|\\/g
exports.getApps = async ctx => { exports.getApps = async ctx => {
let allDbs
// allDbs call of CouchDB is very inaccurate in production // allDbs call of CouchDB is very inaccurate in production
if (env.COUCH_DB_URL) { const allDbs = await CouchDB.allDbs()
allDbs = await (await fetch(`${env.COUCH_DB_URL}/_all_dbs`)).json()
} else {
allDbs = await CouchDB.allDbs()
}
const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX)) const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX))
const appPromises = appDbNames.map(db => const appPromises = appDbNames.map(db =>
new CouchDB(db).get(DocumentTypes.APP_METADATA) new CouchDB(db).get(DocumentTypes.APP_METADATA)

View File

@ -910,7 +910,7 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
asn1@~0.2.0, asn1@~0.2.3: asn1@~0.2.3:
version "0.2.4" version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
@ -1076,7 +1076,7 @@ base@^0.11.1:
mixin-deep "^1.2.0" mixin-deep "^1.2.0"
pascalcase "^0.1.1" pascalcase "^0.1.1"
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: bcrypt-pbkdf@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
@ -1093,15 +1093,6 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
bl@^4.0.3:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
buffer "^5.5.0"
inherits "^2.0.4"
readable-stream "^3.4.0"
boxen@^4.2.0: boxen@^4.2.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
@ -1346,11 +1337,6 @@ chokidar@^3.2.2:
optionalDependencies: optionalDependencies:
fsevents "~2.3.1" fsevents "~2.3.1"
chownr@^1.1.1:
version "1.1.4"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
ci-info@^2.0.0: ci-info@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
@ -1787,24 +1773,6 @@ diff-sequences@^26.6.2:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==
docker-modem@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-3.0.0.tgz#cb912ad8daed42f858269fb3be6944df281ec12d"
integrity sha512-WwFajJ8I5geZ/dDZ5FDMDA6TBkWa76xWwGIGw8uzUjNUGCN0to83wJ8Oi1AxrJTC0JBn+7fvIxUctnawtlwXeg==
dependencies:
debug "^4.1.1"
readable-stream "^3.5.0"
split-ca "^1.0.1"
ssh2 "^0.8.7"
dockerode@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-3.3.0.tgz#bedaf48ef9fa9124275a54a9881a92374c51008e"
integrity sha512-St08lfOjpYCOXEM8XA0VLu3B3hRjtddODphNW5GFoA0AS3JHgoPQKOz0Qmdzg3P+hUPxhb02g1o1Cu1G+U3lRg==
dependencies:
docker-modem "^3.0.0"
tar-fs "~2.0.1"
domexception@^2.0.1: domexception@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
@ -1889,7 +1857,7 @@ encoding-down@^6.3.0:
level-codec "^9.0.0" level-codec "^9.0.0"
level-errors "^2.0.0" level-errors "^2.0.0"
end-of-stream@^1.1.0, end-of-stream@^1.4.1: end-of-stream@^1.1.0:
version "1.4.4" version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
@ -2270,11 +2238,6 @@ fresh@~0.5.2:
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
fs-constants@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs.realpath@^1.0.0: fs.realpath@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@ -4035,11 +3998,6 @@ mixin-deep@^1.2.0:
for-in "^1.0.2" for-in "^1.0.2"
is-extendable "^1.0.1" is-extendable "^1.0.1"
mkdirp-classic@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
mkdirp@^0.5.0: mkdirp@^0.5.0:
version "0.5.5" version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
@ -4871,7 +4829,7 @@ readable-stream@1.1.14:
isarray "0.0.1" isarray "0.0.1"
string_decoder "~0.10.x" string_decoder "~0.10.x"
"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: "readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0:
version "3.6.0" version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@ -5368,11 +5326,6 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ== integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
split-ca@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=
split-string@^3.0.1, split-string@^3.0.2: split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@ -5392,22 +5345,6 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
ssh2-streams@~0.4.10:
version "0.4.10"
resolved "https://registry.yarnpkg.com/ssh2-streams/-/ssh2-streams-0.4.10.tgz#48ef7e8a0e39d8f2921c30521d56dacb31d23a34"
integrity sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==
dependencies:
asn1 "~0.2.0"
bcrypt-pbkdf "^1.0.2"
streamsearch "~0.1.2"
ssh2@^0.8.7:
version "0.8.9"
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-0.8.9.tgz#54da3a6c4ba3daf0d8477a538a481326091815f3"
integrity sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==
dependencies:
ssh2-streams "~0.4.10"
sshpk@^1.7.0: sshpk@^1.7.0:
version "1.16.1" version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
@ -5453,11 +5390,6 @@ stealthy-require@^1.1.1:
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
streamsearch@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
string-length@^4.0.1: string-length@^4.0.1:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@ -5597,27 +5529,6 @@ symbol-tree@^3.2.4:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
tar-fs@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2"
integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==
dependencies:
chownr "^1.1.1"
mkdirp-classic "^0.5.2"
pump "^3.0.0"
tar-stream "^2.0.0"
tar-stream@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
dependencies:
bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
term-size@^2.1.0: term-size@^2.1.0:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54"