Merge branch 'develop' of github.com:Budibase/budibase into side-panel
This commit is contained in:
commit
abedb5d9eb
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "2.1.32-alpha.3",
|
||||
"@budibase/types": "2.1.32-alpha.9",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-sdk": "2.1030.0",
|
||||
|
|
|
@ -171,7 +171,7 @@ export function getGlobalUserParams(globalId: any, otherProps: any = {}) {
|
|||
/**
|
||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||
*/
|
||||
export function getUserMetadataParams(userId?: string, otherProps = {}) {
|
||||
export function getUserMetadataParams(userId?: string | null, otherProps = {}) {
|
||||
return getRowParams(InternalTable.USER_METADATA, userId, otherProps)
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,7 @@ export function getTemplateParams(
|
|||
* Generates a new role ID.
|
||||
* @returns {string} The new role ID which the role doc can be stored under.
|
||||
*/
|
||||
export function generateRoleID(id: any) {
|
||||
export function generateRoleID(id?: any) {
|
||||
return `${DocumentType.ROLE}${SEPARATOR}${id || newid()}`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import { DEFAULT_TENANT_ID } from "../constants"
|
||||
import { doWithDB } from "../db"
|
||||
import { DocumentType, StaticDatabases } from "../db/constants"
|
||||
import { getAllApps } from "../db/utils"
|
||||
import {
|
||||
DocumentType,
|
||||
StaticDatabases,
|
||||
getAllApps,
|
||||
getGlobalDBName,
|
||||
doWithDB,
|
||||
} from "../db"
|
||||
import environment from "../environment"
|
||||
import { doInTenant, getTenantIds, getTenantId } from "../tenancy"
|
||||
import { getGlobalDBName } from "../db/tenancy"
|
||||
import * as context from "../context"
|
||||
import { DEFINITIONS } from "."
|
||||
import {
|
||||
|
|
|
@ -390,7 +390,7 @@ export const uploadDirectory = async (
|
|||
return files
|
||||
}
|
||||
|
||||
exports.downloadTarballDirect = async (
|
||||
export const downloadTarballDirect = async (
|
||||
url: string,
|
||||
path: string,
|
||||
headers = {}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import { BuiltinPermissionID, PermissionLevel } from "./permissions"
|
||||
import {
|
||||
generateRoleID,
|
||||
getRoleParams,
|
||||
DocumentType,
|
||||
SEPARATOR,
|
||||
} from "../db/utils"
|
||||
import { generateRoleID, getRoleParams, DocumentType, SEPARATOR } from "../db"
|
||||
import { getAppDB } from "../context"
|
||||
import { doWithDB } from "../db"
|
||||
import { Screen, Role as RoleDoc } from "@budibase/types"
|
||||
|
@ -30,20 +25,18 @@ const EXTERNAL_BUILTIN_ROLE_IDS = [
|
|||
BUILTIN_IDS.PUBLIC,
|
||||
]
|
||||
|
||||
export class Role {
|
||||
export class Role implements RoleDoc {
|
||||
_id: string
|
||||
_rev?: string
|
||||
name: string
|
||||
permissionId?: string
|
||||
permissionId: string
|
||||
inherits?: string
|
||||
permissions = {}
|
||||
|
||||
constructor(id: string, name: string) {
|
||||
constructor(id: string, name: string, permissionId: string) {
|
||||
this._id = id
|
||||
this.name = name
|
||||
}
|
||||
|
||||
addPermission(permissionId: string) {
|
||||
this.permissionId = permissionId
|
||||
return this
|
||||
}
|
||||
|
||||
addInheritance(inherits: string) {
|
||||
|
@ -53,24 +46,26 @@ export class Role {
|
|||
}
|
||||
|
||||
const BUILTIN_ROLES = {
|
||||
ADMIN: new Role(BUILTIN_IDS.ADMIN, "Admin")
|
||||
.addPermission(BuiltinPermissionID.ADMIN)
|
||||
.addInheritance(BUILTIN_IDS.POWER),
|
||||
POWER: new Role(BUILTIN_IDS.POWER, "Power")
|
||||
.addPermission(BuiltinPermissionID.POWER)
|
||||
.addInheritance(BUILTIN_IDS.BASIC),
|
||||
BASIC: new Role(BUILTIN_IDS.BASIC, "Basic")
|
||||
.addPermission(BuiltinPermissionID.WRITE)
|
||||
.addInheritance(BUILTIN_IDS.PUBLIC),
|
||||
PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public").addPermission(
|
||||
BuiltinPermissionID.PUBLIC
|
||||
),
|
||||
BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder").addPermission(
|
||||
ADMIN: new Role(
|
||||
BUILTIN_IDS.ADMIN,
|
||||
"Admin",
|
||||
BuiltinPermissionID.ADMIN
|
||||
),
|
||||
).addInheritance(BUILTIN_IDS.POWER),
|
||||
POWER: new Role(
|
||||
BUILTIN_IDS.POWER,
|
||||
"Power",
|
||||
BuiltinPermissionID.POWER
|
||||
).addInheritance(BUILTIN_IDS.BASIC),
|
||||
BASIC: new Role(
|
||||
BUILTIN_IDS.BASIC,
|
||||
"Basic",
|
||||
BuiltinPermissionID.WRITE
|
||||
).addInheritance(BUILTIN_IDS.PUBLIC),
|
||||
PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public", BuiltinPermissionID.PUBLIC),
|
||||
BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder", BuiltinPermissionID.ADMIN),
|
||||
}
|
||||
|
||||
export function getBuiltinRoles() {
|
||||
export function getBuiltinRoles(): { [key: string]: RoleDoc } {
|
||||
return cloneDeep(BUILTIN_ROLES)
|
||||
}
|
||||
|
||||
|
@ -104,7 +99,7 @@ export function builtinRoleToNumber(id?: string) {
|
|||
if (!role) {
|
||||
break
|
||||
}
|
||||
role = builtins[role.inherits]
|
||||
role = builtins[role.inherits!]
|
||||
count++
|
||||
} while (role !== null)
|
||||
return count
|
||||
|
@ -129,12 +124,12 @@ export async function roleToNumber(id?: string) {
|
|||
/**
|
||||
* Returns whichever builtin roleID is lower.
|
||||
*/
|
||||
export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string) {
|
||||
export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string): string {
|
||||
if (!roleId1) {
|
||||
return roleId2
|
||||
return roleId2 as string
|
||||
}
|
||||
if (!roleId2) {
|
||||
return roleId1
|
||||
return roleId1 as string
|
||||
}
|
||||
return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2)
|
||||
? roleId2
|
||||
|
|
|
@ -89,6 +89,7 @@ export async function createASession(
|
|||
userId,
|
||||
}
|
||||
await client.store(key, session, EXPIRY_SECONDS)
|
||||
return session
|
||||
}
|
||||
|
||||
export async function updateSessionTTL(session: Session) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||
"@budibase/string-templates": "2.1.32-alpha.3",
|
||||
"@budibase/string-templates": "2.1.32-alpha.9",
|
||||
"@spectrum-css/actionbutton": "^1.0.1",
|
||||
"@spectrum-css/actiongroup": "^1.0.1",
|
||||
"@spectrum-css/avatar": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<div class="skeleton">
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.skeleton {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
background-color: var(--spectrum-global-color-gray-300) !important;
|
||||
border-radius: 7px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
animation: fadeIn 130ms ease 0s 1 normal forwards;
|
||||
}
|
||||
|
||||
.children {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.skeleton::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
background-image: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0) 0,
|
||||
rgba(255, 255, 255, 0.2) 20%,
|
||||
rgba(255, 255, 255, 0.5) 60%,
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
animation: shimmer 2s infinite;
|
||||
content: "";
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -71,7 +71,8 @@
|
|||
visibleRowCount,
|
||||
rowCount,
|
||||
totalRowCount,
|
||||
rowHeight
|
||||
rowHeight,
|
||||
loading
|
||||
)
|
||||
$: sortedRows = sortRows(rows, sortColumn, sortOrder)
|
||||
$: gridStyle = getGridStyle(fields, schema, showEditColumn)
|
||||
|
@ -120,8 +121,12 @@
|
|||
visibleRowCount,
|
||||
rowCount,
|
||||
totalRowCount,
|
||||
rowHeight
|
||||
rowHeight,
|
||||
loading
|
||||
) => {
|
||||
if (loading) {
|
||||
return `height: ${headerHeight + visibleRowCount * rowHeight}px;`
|
||||
}
|
||||
if (!rowCount || !visibleRowCount || totalRowCount <= rowCount) {
|
||||
return ""
|
||||
}
|
||||
|
@ -278,9 +283,11 @@
|
|||
bind:offsetHeight={height}
|
||||
style={`--row-height: ${rowHeight}px; --header-height: ${headerHeight}px;`}
|
||||
>
|
||||
{#if !loaded}
|
||||
{#if loading}
|
||||
<div class="loading" style={heightStyle}>
|
||||
<ProgressCircle />
|
||||
<slot name="loadingIndicator">
|
||||
<ProgressCircle />
|
||||
</slot>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="spectrum-Table" style={`${heightStyle}${gridStyle}`}>
|
||||
|
@ -440,9 +447,10 @@
|
|||
|
||||
/* Loading */
|
||||
.loading {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 100px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Table */
|
||||
|
|
|
@ -4,6 +4,7 @@ import "./bbui.css"
|
|||
import "@spectrum-css/icon/dist/index-vars.css"
|
||||
|
||||
// Components
|
||||
export { default as Skeleton } from "./Skeleton/Skeleton.svelte"
|
||||
export { default as Input } from "./Form/Input.svelte"
|
||||
export { default as Stepper } from "./Form/Stepper.svelte"
|
||||
export { default as TextArea } from "./Form/TextArea.svelte"
|
||||
|
|
|
@ -53,10 +53,10 @@
|
|||
to-gfm-code-block "^0.1.1"
|
||||
year "^0.2.1"
|
||||
|
||||
"@budibase/string-templates@2.1.22-alpha.5":
|
||||
version "2.1.22-alpha.5"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.1.22-alpha.5.tgz#3493be2ec8a3799ad1f7e470c308d9cdcd36abf6"
|
||||
integrity sha512-iFN4nccB8eIjsaU0ki7DyC+zznJaGC+cUQiAiwgO+aDm3SD6vkF443IjwL/fcmpK81/4WpEWmJPDjVuQ+vjlKQ==
|
||||
"@budibase/string-templates@2.1.32-alpha.0":
|
||||
version "2.1.32-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.1.32-alpha.0.tgz#97452a80b3c3238e0d11b48ec36d2d7b8cb8e1d5"
|
||||
integrity sha512-F+AkIWb8CitLt+YCJV/GQB8ECfj7GfO4I/vptIyNay9EWo0MRIU+4Xn715nBfEW5e23BQPKF3QR8S6y0IgxFbg==
|
||||
dependencies:
|
||||
"@budibase/handlebars-helpers" "^0.11.8"
|
||||
dayjs "^1.10.4"
|
||||
|
@ -824,7 +824,7 @@ component-emitter@^1.2.1:
|
|||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||
|
||||
concat-with-sourcemaps@*, concat-with-sourcemaps@^1.1.0:
|
||||
version "1.1.0"
|
||||
|
@ -2080,10 +2080,10 @@ lines-and-columns@^1.1.6:
|
|||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
|
||||
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
|
||||
|
||||
loader-utils@^1.1.0:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.2.tgz#29a957f3a63973883eb684f10ffd3d151fec01a3"
|
||||
integrity sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==
|
||||
loader-utils@1.4.1, loader-utils@^1.1.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.1.tgz#278ad7006660bccc4d2c0c1578e17c5c78d5c0e0"
|
||||
integrity sha512-1Qo97Y2oKaU+Ro2xnDMR26g1BwMT29jNbem1EvcujW2jqt+j5COXyscjM7bLQkM9HaxI7pkWeW7gnI072yMI9Q==
|
||||
dependencies:
|
||||
big.js "^5.2.2"
|
||||
emojis-list "^3.0.0"
|
||||
|
@ -2220,9 +2220,9 @@ mime@1.6.0:
|
|||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ filterTests(['all'], () => {
|
|||
|
||||
it("Should publish an application and correctly reflect that", () => {
|
||||
//Assuming the previous test was run and the unpublished app is open in edit mode.
|
||||
cy.closeModal()
|
||||
cy.get(interact.TOPRIGHTNAV_BUTTON_SPECTRUM).contains("Publish").click({ force : true })
|
||||
|
||||
cy.get(interact.DEPLOY_APP_MODAL).should("be.visible")
|
||||
|
@ -86,8 +85,7 @@ filterTests(['all'], () => {
|
|||
.within(() => {
|
||||
cy.get(interact.APP_TABLE_APP_NAME).click({ force: true })
|
||||
})
|
||||
|
||||
cy.closeModal()
|
||||
|
||||
cy.get(interact.DEPLOYMENT_TOP_GLOBE).should("exist").click({ force: true })
|
||||
|
||||
cy.get("[data-cy='publish-popover-menu']")
|
||||
|
|
|
@ -9,9 +9,10 @@ filterTests(['smoke', 'all'], () => {
|
|||
})
|
||||
|
||||
it("should add a current user binding", () => {
|
||||
cy.searchAndAddComponent("Paragraph").then(() => {
|
||||
cy.searchAndAddComponent("Paragraph").then(componentId => {
|
||||
addSettingBinding("text", ["Current User", "_id"], "Current User._id")
|
||||
})
|
||||
cy.deleteComponentByName("New Paragraph")
|
||||
})
|
||||
|
||||
it("should handle an invalid binding", () => {
|
||||
|
@ -21,6 +22,7 @@ filterTests(['smoke', 'all'], () => {
|
|||
.type("{{}{{}{{} Current User._id {}}{}}")
|
||||
.blur()
|
||||
cy.getComponent(componentId).should("have.text", "{{{ [user].[_id] }}")
|
||||
cy.deleteComponentByName("New Paragraph")
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import filterTests from "../../support/filterTests"
|
||||
|
||||
filterTests(["smoke", "all"], () => {
|
||||
context("REST Datasource Testing", () => {
|
||||
xcontext("REST Datasource Testing", () => {
|
||||
before(() => {
|
||||
cy.login()
|
||||
cy.createTestApp()
|
||||
|
|
|
@ -440,8 +440,8 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => {
|
|||
// Creates an internal Budibase DB table
|
||||
if (!initialTable) {
|
||||
cy.navigateToDataSection()
|
||||
cy.get(`[data-cy="new-datasource"]`, { timeout: 2000 }).click()
|
||||
}
|
||||
cy.get(`[data-cy="new-datasource"]`, { timeout: 2000 }).click()
|
||||
cy.wait(2000)
|
||||
cy.get(".item", { timeout: 2000 })
|
||||
.contains("Budibase DB")
|
||||
|
@ -458,6 +458,9 @@ Cypress.Commands.add("createTable", (tableName, initialTable) => {
|
|||
})
|
||||
// Ensure modal has closed and table is created
|
||||
cy.get(".spectrum-Modal", { timeout: 2000 }).should("not.exist")
|
||||
cy.get(".nav-item", { timeout: 2000 })
|
||||
.contains("Budibase DB")
|
||||
.click({ force: true })
|
||||
cy.get(".spectrum-Tabs-content", { timeout: 2000 }).should(
|
||||
"contain",
|
||||
tableName
|
||||
|
@ -525,7 +528,7 @@ Cypress.Commands.add("addRowMultiValue", values => {
|
|||
})
|
||||
|
||||
Cypress.Commands.add("selectTable", tableName => {
|
||||
cy.expandBudibaseConnection()
|
||||
cy.get(".nav-item").contains("Budibase DB").click()
|
||||
cy.contains(".nav-item", tableName).click()
|
||||
})
|
||||
|
||||
|
@ -576,6 +579,18 @@ Cypress.Commands.add("searchAndAddComponent", component => {
|
|||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add("deleteComponentByName", componentName => {
|
||||
cy.get(".body")
|
||||
.eq(0)
|
||||
.contains(componentName)
|
||||
.siblings(".actions")
|
||||
.within(() => {
|
||||
cy.get(".spectrum-Icon").click({ force: true })
|
||||
})
|
||||
cy.get(".spectrum-Menu").contains("Delete").click()
|
||||
cy.get(".spectrum-Dialog").contains("Delete Component").click()
|
||||
})
|
||||
|
||||
Cypress.Commands.add("addComponent", (category, component) => {
|
||||
if (category) {
|
||||
cy.get(`[data-cy="category-${category}"]`, { timeout: 3000 }).click({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -71,10 +71,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.1.32-alpha.3",
|
||||
"@budibase/client": "2.1.32-alpha.3",
|
||||
"@budibase/frontend-core": "2.1.32-alpha.3",
|
||||
"@budibase/string-templates": "2.1.32-alpha.3",
|
||||
"@budibase/bbui": "2.1.32-alpha.9",
|
||||
"@budibase/client": "2.1.32-alpha.9",
|
||||
"@budibase/frontend-core": "2.1.32-alpha.9",
|
||||
"@budibase/string-templates": "2.1.32-alpha.9",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
@ -26,9 +26,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "2.1.32-alpha.3",
|
||||
"@budibase/string-templates": "2.1.32-alpha.3",
|
||||
"@budibase/types": "2.1.32-alpha.3",
|
||||
"@budibase/backend-core": "2.1.32-alpha.9",
|
||||
"@budibase/string-templates": "2.1.32-alpha.9",
|
||||
"@budibase/types": "2.1.32-alpha.9",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -285,7 +285,7 @@
|
|||
"editable": true,
|
||||
"size": {
|
||||
"width": 105,
|
||||
"height": 35
|
||||
"height": 32
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
|
@ -684,7 +684,7 @@
|
|||
"editable": true,
|
||||
"size": {
|
||||
"width": 400,
|
||||
"height": 30
|
||||
"height": 24
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
|
@ -809,7 +809,7 @@
|
|||
"editable": true,
|
||||
"size": {
|
||||
"width": 400,
|
||||
"height": 40
|
||||
"height": 32
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
|
@ -2448,6 +2448,7 @@
|
|||
]
|
||||
},
|
||||
"stringfield": {
|
||||
"skeleton": false,
|
||||
"name": "Text Field",
|
||||
"icon": "Text",
|
||||
"styles": [
|
||||
|
@ -2456,7 +2457,7 @@
|
|||
"editable": true,
|
||||
"size": {
|
||||
"width": 400,
|
||||
"height": 50
|
||||
"height": 32
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
|
@ -2539,6 +2540,7 @@
|
|||
]
|
||||
},
|
||||
"numberfield": {
|
||||
"skeleton": false,
|
||||
"name": "Number Field",
|
||||
"icon": "123",
|
||||
"styles": [
|
||||
|
@ -2653,6 +2655,7 @@
|
|||
]
|
||||
},
|
||||
"optionsfield": {
|
||||
"skeleton": false,
|
||||
"name": "Options Picker",
|
||||
"icon": "Menu",
|
||||
"styles": [
|
||||
|
@ -2821,6 +2824,7 @@
|
|||
]
|
||||
},
|
||||
"multifieldselect": {
|
||||
"skeleton": false,
|
||||
"name": "Multi-select Picker",
|
||||
"icon": "ViewList",
|
||||
"styles": [
|
||||
|
@ -2983,12 +2987,13 @@
|
|||
]
|
||||
},
|
||||
"booleanfield": {
|
||||
"skeleton": false,
|
||||
"name": "Checkbox",
|
||||
"icon": "SelectBox",
|
||||
"editable": true,
|
||||
"size": {
|
||||
"width": 400,
|
||||
"height": 50
|
||||
"width": 20,
|
||||
"height": 20
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
|
@ -3140,6 +3145,7 @@
|
|||
]
|
||||
},
|
||||
"datetimefield": {
|
||||
"skeleton": false,
|
||||
"name": "Date Picker",
|
||||
"icon": "Date",
|
||||
"styles": [
|
||||
|
@ -3221,6 +3227,7 @@
|
|||
]
|
||||
},
|
||||
"codescanner": {
|
||||
"skeleton": false,
|
||||
"name": "Barcode/QR Scanner",
|
||||
"icon": "Camera",
|
||||
"styles": [
|
||||
|
@ -3386,6 +3393,7 @@
|
|||
]
|
||||
},
|
||||
"attachmentfield": {
|
||||
"skeleton": false,
|
||||
"name": "Attachment",
|
||||
"icon": "Attach",
|
||||
"styles": [
|
||||
|
@ -3444,6 +3452,7 @@
|
|||
]
|
||||
},
|
||||
"relationshipfield": {
|
||||
"skeleton": false,
|
||||
"name": "Relationship Picker",
|
||||
"icon": "TaskList",
|
||||
"styles": [
|
||||
|
@ -3507,6 +3516,7 @@
|
|||
]
|
||||
},
|
||||
"jsonfield": {
|
||||
"skeleton": false,
|
||||
"name": "JSON Field",
|
||||
"icon": "Brackets",
|
||||
"styles": [
|
||||
|
@ -3708,6 +3718,7 @@
|
|||
}
|
||||
},
|
||||
"table": {
|
||||
"skeleton": false,
|
||||
"name": "Table",
|
||||
"icon": "Table",
|
||||
"illegalChildren": [
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.1.32-alpha.3",
|
||||
"@budibase/frontend-core": "2.1.32-alpha.3",
|
||||
"@budibase/string-templates": "2.1.32-alpha.3",
|
||||
"@budibase/bbui": "2.1.32-alpha.9",
|
||||
"@budibase/frontend-core": "2.1.32-alpha.9",
|
||||
"@budibase/string-templates": "2.1.32-alpha.9",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
// to render this part of the block, taking advantage of binding enrichment
|
||||
$: id = `${block.id}-${context ?? rand}`
|
||||
$: instance = {
|
||||
_blockElementHasChildren: $$slots?.default ?? false,
|
||||
_component: `@budibase/standard-components/${type}`,
|
||||
_id: id,
|
||||
_instanceName: name || type[0].toUpperCase() + type.slice(1),
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
import Placeholder from "components/app/Placeholder.svelte"
|
||||
import ScreenPlaceholder from "components/app/ScreenPlaceholder.svelte"
|
||||
import ComponentPlaceholder from "components/app/ComponentPlaceholder.svelte"
|
||||
import Skeleton from "components/app/Skeleton.svelte"
|
||||
|
||||
export let instance = {}
|
||||
export let isLayout = false
|
||||
|
@ -38,6 +39,7 @@
|
|||
|
||||
// Get parent contexts
|
||||
const context = getContext("context")
|
||||
const loading = getContext("loading")
|
||||
const insideScreenslot = !!getContext("screenslot")
|
||||
|
||||
// Create component context
|
||||
|
@ -471,9 +473,21 @@
|
|||
componentStore.actions.unregisterInstance(id)
|
||||
}
|
||||
})
|
||||
|
||||
$: showSkeleton =
|
||||
$loading &&
|
||||
definition.name !== "Screenslot" &&
|
||||
children.length === 0 &&
|
||||
!instance._blockElementHasChildren &&
|
||||
definition.skeleton !== false
|
||||
</script>
|
||||
|
||||
{#if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden}
|
||||
{#if showSkeleton}
|
||||
<Skeleton
|
||||
height={initialSettings?.height || definition?.size?.height || 0}
|
||||
width={initialSettings?.width || definition?.size?.width || 0}
|
||||
/>
|
||||
{:else if constructor && initialSettings && (visible || inSelectedPath) && !builderHidden}
|
||||
<!-- The ID is used as a class because getElementsByClassName is O(1) -->
|
||||
<!-- and the performance matters for the selection indicators -->
|
||||
<div
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { writable } from "svelte/store"
|
||||
import { setContext, getContext, onMount } from "svelte"
|
||||
import Router, { querystring } from "svelte-spa-router"
|
||||
import { routeStore, stateStore } from "stores"
|
||||
|
@ -9,6 +10,9 @@
|
|||
const component = getContext("component")
|
||||
setContext("screenslot", true)
|
||||
|
||||
const loading = writable(false)
|
||||
setContext("loading", loading)
|
||||
|
||||
// Only wrap this as an array to take advantage of svelte keying,
|
||||
// to ensure the svelte-spa-router is fully remounted when route config
|
||||
// changes
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { ProgressCircle, Pagination } from "@budibase/bbui"
|
||||
import { writable } from "svelte/store"
|
||||
import { setContext, getContext } from "svelte"
|
||||
import { Pagination } from "@budibase/bbui"
|
||||
import { fetchData, LuceneUtils } from "@budibase/frontend-core"
|
||||
|
||||
export let dataSource
|
||||
|
@ -10,6 +11,8 @@
|
|||
export let limit
|
||||
export let paginate
|
||||
|
||||
const loading = writable(false)
|
||||
|
||||
const { styleable, Provider, ActionTypes, API } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
|
@ -77,9 +80,13 @@
|
|||
sortColumn: $fetch.sortColumn,
|
||||
sortOrder: $fetch.sortOrder,
|
||||
},
|
||||
loaded: $fetch.loaded,
|
||||
limit: limit,
|
||||
}
|
||||
|
||||
const parentLoading = getContext("loading")
|
||||
setContext("loading", loading)
|
||||
$: loading.set($parentLoading || !$fetch.loaded)
|
||||
|
||||
const createFetch = datasource => {
|
||||
return fetchData({
|
||||
API,
|
||||
|
@ -127,23 +134,17 @@
|
|||
|
||||
<div use:styleable={$component.styles} class="container">
|
||||
<Provider {actions} data={dataContext}>
|
||||
{#if !$fetch.loaded}
|
||||
<div class="loading">
|
||||
<ProgressCircle />
|
||||
<slot />
|
||||
{#if paginate && $fetch.supportsPagination}
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
page={$fetch.pageNumber + 1}
|
||||
hasPrevPage={$fetch.hasPrevPage}
|
||||
hasNextPage={$fetch.hasNextPage}
|
||||
goToPrevPage={fetch.prevPage}
|
||||
goToNextPage={fetch.nextPage}
|
||||
/>
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{#if paginate && $fetch.supportsPagination}
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
page={$fetch.pageNumber + 1}
|
||||
hasPrevPage={$fetch.hasPrevPage}
|
||||
hasNextPage={$fetch.hasNextPage}
|
||||
goToPrevPage={fetch.prevPage}
|
||||
goToNextPage={fetch.nextPage}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</Provider>
|
||||
</div>
|
||||
|
@ -155,13 +156,6 @@
|
|||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
}
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100px;
|
||||
}
|
||||
.pagination {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -12,22 +12,25 @@
|
|||
|
||||
const { Provider } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
const loading = getContext("loading")
|
||||
|
||||
$: rows = dataProvider?.rows ?? []
|
||||
$: loaded = dataProvider?.loaded ?? true
|
||||
// If the parent DataProvider is loading, fill the rows array with a number of empty objects corresponding to the DataProvider's page size; this allows skeleton loader components to be rendered further down the tree.
|
||||
$: rows = $loading
|
||||
? new Array(dataProvider.limit > 20 ? 20 : dataProvider.limit).fill({})
|
||||
: dataProvider?.rows
|
||||
</script>
|
||||
|
||||
<Container {direction} {hAlign} {vAlign} {gap} wrap>
|
||||
{#if $component.empty}
|
||||
<Placeholder />
|
||||
{:else if rows.length > 0}
|
||||
{:else if !$loading && rows.length === 0}
|
||||
<div class="noRows"><i class="ri-list-check-2" />{noRowsMessage}</div>
|
||||
{:else}
|
||||
{#each rows as row, index}
|
||||
<Provider data={{ ...row, index }}>
|
||||
<slot />
|
||||
</Provider>
|
||||
{/each}
|
||||
{:else if loaded && noRowsMessage}
|
||||
<div class="noRows"><i class="ri-list-check-2" />{noRowsMessage}</div>
|
||||
{/if}
|
||||
</Container>
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { Skeleton } from "@budibase/bbui"
|
||||
|
||||
const { styleable } = getContext("sdk")
|
||||
const component = getContext("component")
|
||||
|
||||
export let height
|
||||
export let width
|
||||
|
||||
let styles
|
||||
|
||||
$: {
|
||||
styles = JSON.parse(JSON.stringify($component.styles))
|
||||
|
||||
if (!styles.normal.height && height) {
|
||||
// The height and width props provided to this component can either be numbers or strings set by users (ex. '100%', '100px', '100'). A string of '100' wouldn't be a valid CSS property, but some of our components respect that input, so we need to handle it here also, hence the `!isNaN` check.
|
||||
styles.normal.height = !isNaN(height) ? `${height}px` : height
|
||||
}
|
||||
|
||||
if (!styles.normal.width && width) {
|
||||
styles.normal.width = !isNaN(width) ? `${width}px` : width
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div use:styleable={styles}>
|
||||
<Skeleton>
|
||||
<slot />
|
||||
</Skeleton>
|
||||
</div>
|
|
@ -76,18 +76,26 @@
|
|||
bind:fieldApi
|
||||
defaultValue={[]}
|
||||
>
|
||||
{#if fieldState}
|
||||
<CoreDropzone
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
on:change={handleChange}
|
||||
{processFiles}
|
||||
{deleteAttachments}
|
||||
{handleFileTooLarge}
|
||||
{handleTooManyFiles}
|
||||
{maximum}
|
||||
{extensions}
|
||||
/>
|
||||
{/if}
|
||||
<div class="minHeightWrapper">
|
||||
{#if fieldState}
|
||||
<CoreDropzone
|
||||
value={fieldState.value}
|
||||
disabled={fieldState.disabled}
|
||||
error={fieldState.error}
|
||||
on:change={handleChange}
|
||||
{processFiles}
|
||||
{deleteAttachments}
|
||||
{handleFileTooLarge}
|
||||
{handleTooManyFiles}
|
||||
{maximum}
|
||||
{extensions}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<style>
|
||||
.minHeightWrapper {
|
||||
min-height: 220px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import Placeholder from "../Placeholder.svelte"
|
||||
import FieldGroupFallback from "./FieldGroupFallback.svelte"
|
||||
import Skeleton from "../Skeleton.svelte"
|
||||
import { getContext, onDestroy } from "svelte"
|
||||
|
||||
export let label
|
||||
|
@ -53,6 +54,8 @@
|
|||
builderStore.actions.updateProp("label", e.target.textContent)
|
||||
}
|
||||
|
||||
const loading = getContext("loading")
|
||||
|
||||
onDestroy(() => {
|
||||
fieldApi?.deregister()
|
||||
unsubscribe?.()
|
||||
|
@ -76,6 +79,10 @@
|
|||
<div class="spectrum-Form-itemField">
|
||||
{#if !formContext}
|
||||
<Placeholder text="Form components need to be wrapped in a form" />
|
||||
{:else if $loading}
|
||||
<Skeleton>
|
||||
<slot />
|
||||
</Skeleton>
|
||||
{:else if !fieldState}
|
||||
<Placeholder />
|
||||
{:else if schemaType && schemaType !== type && type !== "options"}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { getContext } from "svelte"
|
||||
import { Table } from "@budibase/bbui"
|
||||
import { Table, Skeleton } from "@budibase/bbui"
|
||||
import SlotRenderer from "./SlotRenderer.svelte"
|
||||
import { UnsortableTypes } from "../../../constants"
|
||||
import { onDestroy } from "svelte"
|
||||
|
@ -14,6 +14,7 @@
|
|||
export let compact
|
||||
export let onClick
|
||||
|
||||
const loading = getContext("loading")
|
||||
const component = getContext("component")
|
||||
const { styleable, getAction, ActionTypes, rowSelectionStore } =
|
||||
getContext("sdk")
|
||||
|
@ -28,7 +29,6 @@
|
|||
let selectedRows = []
|
||||
|
||||
$: hasChildren = $component.children
|
||||
$: loading = dataProvider?.loading ?? false
|
||||
$: data = dataProvider?.rows || []
|
||||
$: fullSchema = dataProvider?.schema ?? {}
|
||||
$: fields = getFields(fullSchema, columns, false)
|
||||
|
@ -130,7 +130,7 @@
|
|||
<Table
|
||||
{data}
|
||||
{schema}
|
||||
{loading}
|
||||
loading={$loading}
|
||||
{rowCount}
|
||||
{quiet}
|
||||
{compact}
|
||||
|
@ -145,6 +145,9 @@
|
|||
on:sort={onSort}
|
||||
on:click={handleClick}
|
||||
>
|
||||
<div class="skeleton" slot="loadingIndicator">
|
||||
<Skeleton />
|
||||
</div>
|
||||
<slot />
|
||||
</Table>
|
||||
{#if allowSelectRows && selectedRows.length}
|
||||
|
@ -159,6 +162,11 @@
|
|||
background-color: var(--spectrum-alias-background-color-secondary);
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.row-count {
|
||||
margin-top: var(--spacing-l);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "2.1.32-alpha.3",
|
||||
"@budibase/bbui": "2.1.32-alpha.9",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/sdk",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"description": "Budibase Public API SDK",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "2.1.32-alpha.3",
|
||||
"version": "2.1.32-alpha.9",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -43,11 +43,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "2.1.32-alpha.3",
|
||||
"@budibase/client": "2.1.32-alpha.3",
|
||||
"@budibase/pro": "2.1.32-alpha.3",
|
||||
"@budibase/string-templates": "2.1.32-alpha.3",
|
||||
"@budibase/types": "2.1.32-alpha.3",
|
||||
"@budibase/backend-core": "2.1.32-alpha.9",
|
||||
"@budibase/client": "2.1.32-alpha.9",
|
||||
"@budibase/pro": "2.1.32-alpha.9",
|
||||
"@budibase/string-templates": "2.1.32-alpha.9",
|
||||
"@budibase/types": "2.1.32-alpha.9",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -3,7 +3,7 @@ const yargs = require("yargs")
|
|||
const fs = require("fs")
|
||||
const { join } = require("path")
|
||||
require("../src/db").init()
|
||||
const { doWithDB } = require("@budibase/backend-core/db")
|
||||
const { db: dbCore } = require("@budibase/backend-core")
|
||||
// load environment
|
||||
const env = require("../src/environment")
|
||||
const {
|
||||
|
@ -48,7 +48,7 @@ yargs
|
|||
const writeStream = fs.createWriteStream(join(exportPath, "dump.text"))
|
||||
// perform couch dump
|
||||
|
||||
await doWithDB(appId, async db => {
|
||||
await dbCore.doWithDB(appId, async db => {
|
||||
return db.dump(writeStream, {
|
||||
filter: doc =>
|
||||
!(
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
const { StaticDatabases } = require("@budibase/backend-core/db")
|
||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
||||
import { db as dbCore, tenancy } from "@budibase/backend-core"
|
||||
import { BBContext, Document } from "@budibase/types"
|
||||
|
||||
const KEYS_DOC = StaticDatabases.GLOBAL.docs.apiKeys
|
||||
const KEYS_DOC = dbCore.StaticDatabases.GLOBAL.docs.apiKeys
|
||||
|
||||
async function getBuilderMainDoc() {
|
||||
const db = getGlobalDB()
|
||||
const db = tenancy.getGlobalDB()
|
||||
try {
|
||||
return await db.get(KEYS_DOC)
|
||||
} catch (err) {
|
||||
|
@ -15,24 +15,24 @@ async function getBuilderMainDoc() {
|
|||
}
|
||||
}
|
||||
|
||||
async function setBuilderMainDoc(doc) {
|
||||
async function setBuilderMainDoc(doc: Document) {
|
||||
// make sure to override the ID
|
||||
doc._id = KEYS_DOC
|
||||
const db = getGlobalDB()
|
||||
const db = tenancy.getGlobalDB()
|
||||
return db.put(doc)
|
||||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
export async function fetch(ctx: BBContext) {
|
||||
try {
|
||||
const mainDoc = await getBuilderMainDoc()
|
||||
ctx.body = mainDoc.apiKeys ? mainDoc.apiKeys : {}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
/* istanbul ignore next */
|
||||
ctx.throw(400, err)
|
||||
}
|
||||
}
|
||||
|
||||
exports.update = async function (ctx) {
|
||||
export async function update(ctx: BBContext) {
|
||||
const key = ctx.params.key
|
||||
const value = ctx.request.body.value
|
||||
|
||||
|
@ -47,7 +47,7 @@ exports.update = async function (ctx) {
|
|||
_id: resp.id,
|
||||
_rev: resp.rev,
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
/* istanbul ignore next */
|
||||
ctx.throw(400, err)
|
||||
}
|
|
@ -3,7 +3,7 @@ import { InternalTables } from "../../db/utils"
|
|||
import { getFullUser } from "../../utilities/users"
|
||||
import { roles, context } from "@budibase/backend-core"
|
||||
import { groups } from "@budibase/pro"
|
||||
import { ContextUser, User } from "@budibase/types"
|
||||
import { ContextUser, User, Row } from "@budibase/types"
|
||||
|
||||
const PUBLIC_ROLE = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
|
||||
|
@ -43,7 +43,7 @@ export async function fetchSelf(ctx: any) {
|
|||
try {
|
||||
const userTable = await db.get(InternalTables.USER_METADATA)
|
||||
// specifically needs to make sure is enriched
|
||||
ctx.body = await outputProcessing(userTable, user)
|
||||
ctx.body = await outputProcessing(userTable, user as Row)
|
||||
} catch (err: any) {
|
||||
let response
|
||||
// user didn't exist in app, don't pretend they do
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
const actions = require("../../automations/actions")
|
||||
const triggers = require("../../automations/triggers")
|
||||
const {
|
||||
import actions from "../../automations/actions"
|
||||
import triggers from "../../automations/triggers"
|
||||
import {
|
||||
getAutomationParams,
|
||||
generateAutomationID,
|
||||
DocumentType,
|
||||
} = require("../../db/utils")
|
||||
const {
|
||||
} from "../../db/utils"
|
||||
import {
|
||||
checkForWebhooks,
|
||||
updateTestHistory,
|
||||
removeDeprecated,
|
||||
} = require("../../automations/utils")
|
||||
const { deleteEntityMetadata } = require("../../utilities")
|
||||
const { MetadataTypes } = require("../../constants")
|
||||
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
||||
const {
|
||||
getAppDB,
|
||||
getProdAppDB,
|
||||
doInAppContext,
|
||||
} = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
const { app } = require("@budibase/backend-core/cache")
|
||||
const { automations } = require("@budibase/pro")
|
||||
} from "../../automations/utils"
|
||||
import { deleteEntityMetadata } from "../../utilities"
|
||||
import { MetadataTypes } from "../../constants"
|
||||
import { setTestFlag, clearTestFlag } from "../../utilities/redis"
|
||||
import { context, cache, events } from "@budibase/backend-core"
|
||||
import { automations } from "@budibase/pro"
|
||||
import { Automation, BBContext } from "@budibase/types"
|
||||
|
||||
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
|
||||
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
||||
|
@ -31,7 +26,7 @@ const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
|||
* *
|
||||
*************************/
|
||||
|
||||
async function cleanupAutomationMetadata(automationId) {
|
||||
async function cleanupAutomationMetadata(automationId: string) {
|
||||
await deleteEntityMetadata(MetadataTypes.AUTOMATION_TEST_INPUT, automationId)
|
||||
await deleteEntityMetadata(
|
||||
MetadataTypes.AUTOMATION_TEST_HISTORY,
|
||||
|
@ -39,7 +34,7 @@ async function cleanupAutomationMetadata(automationId) {
|
|||
)
|
||||
}
|
||||
|
||||
function cleanAutomationInputs(automation) {
|
||||
function cleanAutomationInputs(automation: Automation) {
|
||||
if (automation == null) {
|
||||
return automation
|
||||
}
|
||||
|
@ -63,14 +58,14 @@ function cleanAutomationInputs(automation) {
|
|||
return automation
|
||||
}
|
||||
|
||||
exports.create = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function create(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let automation = ctx.request.body
|
||||
automation.appId = ctx.appId
|
||||
|
||||
// call through to update if already exists
|
||||
if (automation._id && automation._rev) {
|
||||
return exports.update(ctx)
|
||||
return update(ctx)
|
||||
}
|
||||
|
||||
automation._id = generateAutomationID()
|
||||
|
@ -97,17 +92,23 @@ exports.create = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
const getNewSteps = (oldAutomation, automation) => {
|
||||
export function getNewSteps(oldAutomation: Automation, automation: Automation) {
|
||||
const oldStepIds = oldAutomation.definition.steps.map(s => s.id)
|
||||
return automation.definition.steps.filter(s => !oldStepIds.includes(s.id))
|
||||
}
|
||||
|
||||
const getDeletedSteps = (oldAutomation, automation) => {
|
||||
export function getDeletedSteps(
|
||||
oldAutomation: Automation,
|
||||
automation: Automation
|
||||
) {
|
||||
const stepIds = automation.definition.steps.map(s => s.id)
|
||||
return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id))
|
||||
}
|
||||
|
||||
const handleStepEvents = async (oldAutomation, automation) => {
|
||||
export async function handleStepEvents(
|
||||
oldAutomation: Automation,
|
||||
automation: Automation
|
||||
) {
|
||||
// new steps
|
||||
const newSteps = getNewSteps(oldAutomation, automation)
|
||||
for (let step of newSteps) {
|
||||
|
@ -121,8 +122,8 @@ const handleStepEvents = async (oldAutomation, automation) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.update = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function update(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let automation = ctx.request.body
|
||||
automation.appId = ctx.appId
|
||||
const oldAutomation = await db.get(automation._id)
|
||||
|
@ -146,9 +147,8 @@ exports.update = async function (ctx) {
|
|||
if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) {
|
||||
await events.automation.triggerUpdated(automation)
|
||||
await deleteEntityMetadata(
|
||||
ctx.appId,
|
||||
MetadataTypes.AUTOMATION_TEST_INPUT,
|
||||
automation._id
|
||||
automation._id!
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -165,8 +165,8 @@ exports.update = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function fetch(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const response = await db.allDocs(
|
||||
getAutomationParams(null, {
|
||||
include_docs: true,
|
||||
|
@ -175,13 +175,13 @@ exports.fetch = async function (ctx) {
|
|||
ctx.body = response.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function find(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
ctx.body = await db.get(ctx.params.id)
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const automationId = ctx.params.id
|
||||
const oldAutomation = await db.get(automationId)
|
||||
await checkForWebhooks({
|
||||
|
@ -193,14 +193,14 @@ exports.destroy = async function (ctx) {
|
|||
await events.automation.deleted(oldAutomation)
|
||||
}
|
||||
|
||||
exports.logSearch = async function (ctx) {
|
||||
export async function logSearch(ctx: BBContext) {
|
||||
ctx.body = await automations.logs.logSearch(ctx.request.body)
|
||||
}
|
||||
|
||||
exports.clearLogError = async function (ctx) {
|
||||
export async function clearLogError(ctx: BBContext) {
|
||||
const { automationId, appId } = ctx.request.body
|
||||
await doInAppContext(appId, async () => {
|
||||
const db = getProdAppDB()
|
||||
await context.doInAppContext(appId, async () => {
|
||||
const db = context.getProdAppDB()
|
||||
const metadata = await db.get(DocumentType.APP_METADATA)
|
||||
if (!automationId) {
|
||||
delete metadata.automationErrors
|
||||
|
@ -211,20 +211,20 @@ exports.clearLogError = async function (ctx) {
|
|||
delete metadata.automationErrors[automationId]
|
||||
}
|
||||
await db.put(metadata)
|
||||
await app.invalidateAppMetadata(metadata.appId, metadata)
|
||||
await cache.app.invalidateAppMetadata(metadata.appId, metadata)
|
||||
ctx.body = { message: `Error logs cleared.` }
|
||||
})
|
||||
}
|
||||
|
||||
exports.getActionList = async function (ctx) {
|
||||
export async function getActionList(ctx: BBContext) {
|
||||
ctx.body = ACTION_DEFS
|
||||
}
|
||||
|
||||
exports.getTriggerList = async function (ctx) {
|
||||
export async function getTriggerList(ctx: BBContext) {
|
||||
ctx.body = TRIGGER_DEFS
|
||||
}
|
||||
|
||||
module.exports.getDefinitionList = async function (ctx) {
|
||||
export async function getDefinitionList(ctx: BBContext) {
|
||||
ctx.body = {
|
||||
trigger: TRIGGER_DEFS,
|
||||
action: ACTION_DEFS,
|
||||
|
@ -237,8 +237,8 @@ module.exports.getDefinitionList = async function (ctx) {
|
|||
* *
|
||||
*********************/
|
||||
|
||||
exports.trigger = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function trigger(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let automation = await db.get(ctx.params.id)
|
||||
await triggers.externalTrigger(automation, {
|
||||
...ctx.request.body,
|
||||
|
@ -250,7 +250,7 @@ exports.trigger = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
function prepareTestInput(input) {
|
||||
function prepareTestInput(input: any) {
|
||||
// prepare the test parameters
|
||||
if (input.id && input.row) {
|
||||
input.row._id = input.id
|
||||
|
@ -261,8 +261,8 @@ function prepareTestInput(input) {
|
|||
return input
|
||||
}
|
||||
|
||||
exports.test = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function test(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let automation = await db.get(ctx.params.id)
|
||||
await setTestFlag(automation._id)
|
||||
const testInput = prepareTestInput(ctx.request.body)
|
|
@ -1,14 +1,14 @@
|
|||
const env = require("../../environment")
|
||||
const { getAllApps, getGlobalDBName } = require("@budibase/backend-core/db")
|
||||
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
||||
const { streamFile } = require("../../utilities/fileSystem")
|
||||
const { stringToReadStream } = require("../../utilities")
|
||||
const { getDocParams, DocumentType, isDevAppID } = require("../../db/utils")
|
||||
const { create } = require("./application")
|
||||
const { join } = require("path")
|
||||
const sdk = require("../../sdk")
|
||||
import env from "../../environment"
|
||||
import { db as dbCore, tenancy } from "@budibase/backend-core"
|
||||
import { streamFile } from "../../utilities/fileSystem"
|
||||
import { stringToReadStream } from "../../utilities"
|
||||
import { getDocParams, DocumentType, isDevAppID } from "../../db/utils"
|
||||
import { create } from "./application"
|
||||
import { join } from "path"
|
||||
import { App, BBContext, Database } from "@budibase/types"
|
||||
import sdk from "../../sdk"
|
||||
|
||||
async function createApp(appName, appDirectory) {
|
||||
async function createApp(appName: string, appDirectory: string) {
|
||||
const ctx = {
|
||||
request: {
|
||||
body: {
|
||||
|
@ -25,7 +25,7 @@ async function createApp(appName, appDirectory) {
|
|||
return create(ctx)
|
||||
}
|
||||
|
||||
async function getAllDocType(db, docType) {
|
||||
async function getAllDocType(db: Database, docType: string) {
|
||||
const response = await db.allDocs(
|
||||
getDocParams(docType, null, {
|
||||
include_docs: true,
|
||||
|
@ -34,19 +34,19 @@ async function getAllDocType(db, docType) {
|
|||
return response.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
exports.exportApps = async ctx => {
|
||||
export async function exportApps(ctx: BBContext) {
|
||||
if (env.SELF_HOSTED || !env.MULTI_TENANCY) {
|
||||
ctx.throw(400, "Exporting only allowed in multi-tenant cloud environments.")
|
||||
}
|
||||
const apps = await getAllApps({ all: true })
|
||||
const globalDBString = await sdk.backups.exportDB(getGlobalDBName(), {
|
||||
filter: doc => !doc._id.startsWith(DocumentType.USER),
|
||||
const apps = (await dbCore.getAllApps({ all: true })) as App[]
|
||||
const globalDBString = await sdk.backups.exportDB(dbCore.getGlobalDBName(), {
|
||||
filter: (doc: any) => !doc._id.startsWith(DocumentType.USER),
|
||||
})
|
||||
// only export the dev apps as they will be the latest, the user can republish the apps
|
||||
// in their self-hosted environment
|
||||
let appMetadata = apps
|
||||
.filter(app => isDevAppID(app.appId || app._id))
|
||||
.map(app => ({ appId: app.appId || app._id, name: app.name }))
|
||||
.filter((app: App) => isDevAppID(app.appId || app._id))
|
||||
.map((app: App) => ({ appId: (app.appId || app._id)!, name: app.name }))
|
||||
const tmpPath = await sdk.backups.exportMultipleApps(
|
||||
appMetadata,
|
||||
globalDBString
|
||||
|
@ -56,25 +56,25 @@ exports.exportApps = async ctx => {
|
|||
ctx.body = streamFile(tmpPath)
|
||||
}
|
||||
|
||||
async function hasBeenImported() {
|
||||
async function checkHasBeenImported() {
|
||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
||||
return true
|
||||
}
|
||||
const apps = await getAllApps({ all: true })
|
||||
const apps = await dbCore.getAllApps({ all: true })
|
||||
return apps.length !== 0
|
||||
}
|
||||
|
||||
exports.hasBeenImported = async ctx => {
|
||||
export async function hasBeenImported(ctx: BBContext) {
|
||||
ctx.body = {
|
||||
imported: await hasBeenImported(),
|
||||
imported: await checkHasBeenImported(),
|
||||
}
|
||||
}
|
||||
|
||||
exports.importApps = async ctx => {
|
||||
export async function importApps(ctx: BBContext) {
|
||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
||||
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
||||
}
|
||||
const beenImported = await hasBeenImported()
|
||||
const beenImported = await checkHasBeenImported()
|
||||
if (beenImported || !ctx.request.files || !ctx.request.files.importFile) {
|
||||
ctx.throw(
|
||||
400,
|
||||
|
@ -90,7 +90,7 @@ exports.importApps = async ctx => {
|
|||
const globalDbImport = sdk.backups.getGlobalDBFile(tmpPath)
|
||||
const appNames = sdk.backups.getListOfAppsInMulti(tmpPath)
|
||||
|
||||
const globalDb = getGlobalDB()
|
||||
const globalDb = tenancy.getGlobalDB()
|
||||
// load the global db first
|
||||
await globalDb.load(stringToReadStream(globalDbImport))
|
||||
for (let appName of appNames) {
|
|
@ -2,8 +2,9 @@ import { DocumentType } from "../../db/utils"
|
|||
import { Plugin } from "@budibase/types"
|
||||
import { db as dbCore, context, tenancy } from "@budibase/backend-core"
|
||||
import { getComponentLibraryManifest } from "../../utilities/fileSystem"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
exports.fetchAppComponentDefinitions = async function (ctx: any) {
|
||||
export async function fetchAppComponentDefinitions(ctx: BBContext) {
|
||||
try {
|
||||
const db = context.getAppDB()
|
||||
const app = await db.get(DocumentType.APP_METADATA)
|
||||
|
|
|
@ -1,30 +1,29 @@
|
|||
const {
|
||||
import {
|
||||
generateDatasourceID,
|
||||
getDatasourceParams,
|
||||
getQueryParams,
|
||||
DocumentType,
|
||||
BudibaseInternalDB,
|
||||
getTableParams,
|
||||
} = require("../../db/utils")
|
||||
const { destroy: tableDestroy } = require("./table/internal")
|
||||
const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
|
||||
const { getIntegration } = require("../../integrations")
|
||||
const { getDatasourceAndQuery } = require("./row/utils")
|
||||
const { invalidateDynamicVariables } = require("../../threads/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
const { db: dbCore } = require("@budibase/backend-core")
|
||||
} from "../../db/utils"
|
||||
import { destroy as tableDestroy } from "./table/internal"
|
||||
import { BuildSchemaErrors, InvalidColumns } from "../../constants"
|
||||
import { getIntegration } from "../../integrations"
|
||||
import { getDatasourceAndQuery } from "./row/utils"
|
||||
import { invalidateDynamicVariables } from "../../threads/utils"
|
||||
import { db as dbCore, context, events } from "@budibase/backend-core"
|
||||
import { BBContext, Datasource, Row } from "@budibase/types"
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
export async function fetch(ctx: BBContext) {
|
||||
// Get internal tables
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const internalTables = await db.allDocs(
|
||||
getTableParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
|
||||
const internal = internalTables.rows.reduce((acc, row) => {
|
||||
const internal = internalTables.rows.reduce((acc: any, row: Row) => {
|
||||
const sourceId = row.doc.sourceId || "bb_internal"
|
||||
acc[sourceId] = acc[sourceId] || []
|
||||
acc[sourceId].push(row.doc)
|
||||
|
@ -60,8 +59,8 @@ exports.fetch = async function (ctx) {
|
|||
ctx.body = [bbInternalDb, ...datasources]
|
||||
}
|
||||
|
||||
exports.buildSchemaFromDb = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function buildSchemaFromDb(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const datasource = await db.get(ctx.params.datasourceId)
|
||||
const tablesFilter = ctx.request.body.tablesFilter
|
||||
|
||||
|
@ -72,7 +71,9 @@ exports.buildSchemaFromDb = async function (ctx) {
|
|||
}
|
||||
for (let key in tables) {
|
||||
if (
|
||||
tablesFilter.some(filter => filter.toLowerCase() === key.toLowerCase())
|
||||
tablesFilter.some(
|
||||
(filter: any) => filter.toLowerCase() === key.toLowerCase()
|
||||
)
|
||||
) {
|
||||
datasource.entities[key] = tables[key]
|
||||
}
|
||||
|
@ -85,7 +86,7 @@ exports.buildSchemaFromDb = async function (ctx) {
|
|||
const dbResp = await db.put(datasource)
|
||||
datasource._rev = dbResp.rev
|
||||
|
||||
const response = { datasource }
|
||||
const response: any = { datasource }
|
||||
if (error) {
|
||||
response.error = error
|
||||
}
|
||||
|
@ -95,9 +96,9 @@ exports.buildSchemaFromDb = async function (ctx) {
|
|||
/**
|
||||
* Make sure all datasource entities have a display name selected
|
||||
*/
|
||||
const setDefaultDisplayColumns = datasource => {
|
||||
function setDefaultDisplayColumns(datasource: Datasource) {
|
||||
//
|
||||
for (let entity of Object.values(datasource.entities)) {
|
||||
for (let entity of Object.values(datasource.entities || {})) {
|
||||
if (entity.primaryDisplay) {
|
||||
continue
|
||||
}
|
||||
|
@ -113,9 +114,12 @@ const setDefaultDisplayColumns = datasource => {
|
|||
/**
|
||||
* Check for variables that have been updated or removed and invalidate them.
|
||||
*/
|
||||
const invalidateVariables = async (existingDatasource, updatedDatasource) => {
|
||||
const existingVariables = existingDatasource.config.dynamicVariables
|
||||
const updatedVariables = updatedDatasource.config.dynamicVariables
|
||||
async function invalidateVariables(
|
||||
existingDatasource: Datasource,
|
||||
updatedDatasource: Datasource
|
||||
) {
|
||||
const existingVariables: any = existingDatasource.config?.dynamicVariables
|
||||
const updatedVariables: any = updatedDatasource.config?.dynamicVariables
|
||||
const toInvalidate = []
|
||||
|
||||
if (!existingVariables) {
|
||||
|
@ -127,9 +131,9 @@ const invalidateVariables = async (existingDatasource, updatedDatasource) => {
|
|||
toInvalidate.push(...existingVariables)
|
||||
} else {
|
||||
// invaldate changed / removed
|
||||
existingVariables.forEach(existing => {
|
||||
existingVariables.forEach((existing: any) => {
|
||||
const unchanged = updatedVariables.find(
|
||||
updated =>
|
||||
(updated: any) =>
|
||||
existing.name === updated.name &&
|
||||
existing.queryId === updated.queryId &&
|
||||
existing.value === updated.value
|
||||
|
@ -142,8 +146,8 @@ const invalidateVariables = async (existingDatasource, updatedDatasource) => {
|
|||
await invalidateDynamicVariables(toInvalidate)
|
||||
}
|
||||
|
||||
exports.update = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function update(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const datasourceId = ctx.params.datasourceId
|
||||
let datasource = await db.get(datasourceId)
|
||||
const auth = datasource.config.auth
|
||||
|
@ -171,8 +175,8 @@ exports.update = async function (ctx) {
|
|||
ctx.body = { datasource }
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function save(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const plus = ctx.request.body.datasource.plus
|
||||
const fetchSchema = ctx.request.body.fetchSchema
|
||||
|
||||
|
@ -202,15 +206,15 @@ exports.save = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
const response = { datasource }
|
||||
const response: any = { datasource }
|
||||
if (schemaError) {
|
||||
response.error = schemaError
|
||||
}
|
||||
ctx.body = response
|
||||
}
|
||||
|
||||
const destroyInternalTablesBySourceId = async datasourceId => {
|
||||
const db = getAppDB()
|
||||
async function destroyInternalTablesBySourceId(datasourceId: string) {
|
||||
const db = context.getAppDB()
|
||||
|
||||
// Get all internal tables
|
||||
const internalTables = await db.allDocs(
|
||||
|
@ -220,12 +224,15 @@ const destroyInternalTablesBySourceId = async datasourceId => {
|
|||
)
|
||||
|
||||
// Filter by datasource and return the docs.
|
||||
const datasourceTableDocs = internalTables.rows.reduce((acc, table) => {
|
||||
if (table.doc.sourceId == datasourceId) {
|
||||
acc.push(table.doc)
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
const datasourceTableDocs = internalTables.rows.reduce(
|
||||
(acc: any, table: any) => {
|
||||
if (table.doc.sourceId == datasourceId) {
|
||||
acc.push(table.doc)
|
||||
}
|
||||
return acc
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
// Destroy the tables.
|
||||
for (const table of datasourceTableDocs) {
|
||||
|
@ -237,8 +244,8 @@ const destroyInternalTablesBySourceId = async datasourceId => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const datasourceId = ctx.params.datasourceId
|
||||
|
||||
const datasource = await db.get(datasourceId)
|
||||
|
@ -249,7 +256,7 @@ exports.destroy = async function (ctx) {
|
|||
} else {
|
||||
const queries = await db.allDocs(getQueryParams(datasourceId, null))
|
||||
await db.bulkDocs(
|
||||
queries.rows.map(row => ({
|
||||
queries.rows.map((row: any) => ({
|
||||
_id: row.id,
|
||||
_rev: row.value.rev,
|
||||
_deleted: true,
|
||||
|
@ -265,28 +272,28 @@ exports.destroy = async function (ctx) {
|
|||
ctx.status = 200
|
||||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
const database = getAppDB()
|
||||
export async function find(ctx: BBContext) {
|
||||
const database = context.getAppDB()
|
||||
ctx.body = await database.get(ctx.params.datasourceId)
|
||||
}
|
||||
|
||||
// dynamic query functionality
|
||||
exports.query = async function (ctx) {
|
||||
export async function query(ctx: BBContext) {
|
||||
const queryJson = ctx.request.body
|
||||
try {
|
||||
ctx.body = await getDatasourceAndQuery(queryJson)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
ctx.throw(400, err)
|
||||
}
|
||||
}
|
||||
|
||||
function getErrorTables(errors, errorType) {
|
||||
function getErrorTables(errors: any, errorType: string) {
|
||||
return Object.entries(errors)
|
||||
.filter(entry => entry[1] === errorType)
|
||||
.map(([name]) => name)
|
||||
}
|
||||
|
||||
function updateError(error, newError, tables) {
|
||||
function updateError(error: any, newError: any, tables: string[]) {
|
||||
if (!error) {
|
||||
error = ""
|
||||
}
|
||||
|
@ -297,7 +304,7 @@ function updateError(error, newError, tables) {
|
|||
return error
|
||||
}
|
||||
|
||||
const buildSchemaHelper = async datasource => {
|
||||
async function buildSchemaHelper(datasource: Datasource) {
|
||||
const Connector = await getIntegration(datasource.source)
|
||||
|
||||
// Connect to the DB and build the schema
|
|
@ -1,15 +1,20 @@
|
|||
const newid = require("../../../db/newid")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
import newid from "../../../db/newid"
|
||||
import { context } from "@budibase/backend-core"
|
||||
|
||||
/**
|
||||
* This is used to pass around information about the deployment that is occurring
|
||||
*/
|
||||
class Deployment {
|
||||
export default class Deployment {
|
||||
_id: string
|
||||
verification: any
|
||||
status?: string
|
||||
err?: any
|
||||
|
||||
constructor(id = null) {
|
||||
this._id = id || newid()
|
||||
}
|
||||
|
||||
setVerification(verification) {
|
||||
setVerification(verification: any) {
|
||||
if (!verification) {
|
||||
return
|
||||
}
|
||||
|
@ -20,14 +25,14 @@ class Deployment {
|
|||
return this.verification
|
||||
}
|
||||
|
||||
setStatus(status, err = null) {
|
||||
setStatus(status: string, err?: any) {
|
||||
this.status = status
|
||||
if (err) {
|
||||
this.err = err
|
||||
}
|
||||
}
|
||||
|
||||
fromJSON(json) {
|
||||
fromJSON(json: any) {
|
||||
if (json.verification) {
|
||||
this.setVerification(json.verification)
|
||||
}
|
||||
|
@ -37,9 +42,9 @@ class Deployment {
|
|||
}
|
||||
|
||||
getJSON() {
|
||||
const obj = {
|
||||
const obj: any = {
|
||||
_id: this._id,
|
||||
appId: getAppId(),
|
||||
appId: context.getAppId(),
|
||||
status: this.status,
|
||||
}
|
||||
if (this.err) {
|
||||
|
@ -51,5 +56,3 @@ class Deployment {
|
|||
return obj
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Deployment
|
|
@ -1,10 +1,10 @@
|
|||
const { EMPTY_LAYOUT } = require("../../constants/layouts")
|
||||
const { generateLayoutID, getScreenParams } = require("../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
import { EMPTY_LAYOUT } from "../../constants/layouts"
|
||||
import { generateLayoutID, getScreenParams } from "../../db/utils"
|
||||
import { events, context } from "@budibase/backend-core"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function save(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let layout = ctx.request.body
|
||||
|
||||
if (!layout.props) {
|
||||
|
@ -24,8 +24,8 @@ exports.save = async function (ctx) {
|
|||
ctx.status = 200
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const layoutId = ctx.params.layoutId,
|
||||
layoutRev = ctx.params.layoutRev
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
const { MetadataTypes } = require("../../constants")
|
||||
const { generateMetadataID } = require("../../db/utils")
|
||||
const { saveEntityMetadata, deleteEntityMetadata } = require("../../utilities")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
import { MetadataTypes } from "../../constants"
|
||||
import { generateMetadataID } from "../../db/utils"
|
||||
import { saveEntityMetadata, deleteEntityMetadata } from "../../utilities"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
exports.getTypes = async ctx => {
|
||||
export async function getTypes(ctx: BBContext) {
|
||||
ctx.body = {
|
||||
types: MetadataTypes,
|
||||
}
|
||||
}
|
||||
|
||||
exports.saveMetadata = async ctx => {
|
||||
export async function saveMetadata(ctx: BBContext) {
|
||||
const { type, entityId } = ctx.params
|
||||
if (type === MetadataTypes.AUTOMATION_TEST_HISTORY) {
|
||||
ctx.throw(400, "Cannot save automation history type")
|
||||
|
@ -17,7 +18,7 @@ exports.saveMetadata = async ctx => {
|
|||
ctx.body = await saveEntityMetadata(type, entityId, ctx.request.body)
|
||||
}
|
||||
|
||||
exports.deleteMetadata = async ctx => {
|
||||
export async function deleteMetadata(ctx: BBContext) {
|
||||
const { type, entityId } = ctx.params
|
||||
await deleteEntityMetadata(type, entityId)
|
||||
ctx.body = {
|
||||
|
@ -25,13 +26,13 @@ exports.deleteMetadata = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getMetadata = async ctx => {
|
||||
export async function getMetadata(ctx: BBContext) {
|
||||
const { type, entityId } = ctx.params
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const id = generateMetadataID(type, entityId)
|
||||
try {
|
||||
ctx.body = await db.get(id)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.status === 404) {
|
||||
ctx.body = {}
|
||||
} else {
|
|
@ -1,18 +1,11 @@
|
|||
const { getBuiltinPermissions } = require("@budibase/backend-core/permissions")
|
||||
const {
|
||||
isBuiltin,
|
||||
getDBRoleID,
|
||||
getExternalRoleID,
|
||||
getBuiltinRoles,
|
||||
checkForRoleResourceArray,
|
||||
} = require("@budibase/backend-core/roles")
|
||||
const { getRoleParams } = require("../../db/utils")
|
||||
const {
|
||||
import { permissions, roles, context } from "@budibase/backend-core"
|
||||
import { getRoleParams } from "../../db/utils"
|
||||
import {
|
||||
CURRENTLY_SUPPORTED_LEVELS,
|
||||
getBasePermissions,
|
||||
} = require("../../utilities/security")
|
||||
const { removeFromArray } = require("../../utilities")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
} from "../../utilities/security"
|
||||
import { removeFromArray } from "../../utilities"
|
||||
import { BBContext, Database, Role } from "@budibase/types"
|
||||
|
||||
const PermissionUpdateType = {
|
||||
REMOVE: "remove",
|
||||
|
@ -22,7 +15,7 @@ const PermissionUpdateType = {
|
|||
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
||||
|
||||
// utility function to stop this repetition - permissions always stored under roles
|
||||
async function getAllDBRoles(db) {
|
||||
async function getAllDBRoles(db: Database) {
|
||||
const body = await db.allDocs(
|
||||
getRoleParams(null, {
|
||||
include_docs: true,
|
||||
|
@ -32,21 +25,25 @@ async function getAllDBRoles(db) {
|
|||
}
|
||||
|
||||
async function updatePermissionOnRole(
|
||||
appId,
|
||||
{ roleId, resourceId, level },
|
||||
updateType
|
||||
appId: string,
|
||||
{
|
||||
roleId,
|
||||
resourceId,
|
||||
level,
|
||||
}: { roleId: string; resourceId: string; level: string },
|
||||
updateType: string
|
||||
) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const remove = updateType === PermissionUpdateType.REMOVE
|
||||
const isABuiltin = isBuiltin(roleId)
|
||||
const dbRoleId = getDBRoleID(roleId)
|
||||
const isABuiltin = roles.isBuiltin(roleId)
|
||||
const dbRoleId = roles.getDBRoleID(roleId)
|
||||
const dbRoles = await getAllDBRoles(db)
|
||||
const docUpdates = []
|
||||
|
||||
// the permission is for a built in, make sure it exists
|
||||
if (isABuiltin && !dbRoles.some(role => role._id === dbRoleId)) {
|
||||
const builtin = getBuiltinRoles()[roleId]
|
||||
builtin._id = getDBRoleID(builtin._id)
|
||||
const builtin = roles.getBuiltinRoles()[roleId]
|
||||
builtin._id = roles.getDBRoleID(builtin._id)
|
||||
dbRoles.push(builtin)
|
||||
}
|
||||
|
||||
|
@ -90,41 +87,44 @@ async function updatePermissionOnRole(
|
|||
}
|
||||
|
||||
const response = await db.bulkDocs(docUpdates)
|
||||
return response.map(resp => {
|
||||
resp._id = getExternalRoleID(resp.id)
|
||||
return response.map((resp: any) => {
|
||||
resp._id = roles.getExternalRoleID(resp.id)
|
||||
delete resp.id
|
||||
return resp
|
||||
})
|
||||
}
|
||||
|
||||
exports.fetchBuiltin = function (ctx) {
|
||||
ctx.body = Object.values(getBuiltinPermissions())
|
||||
export function fetchBuiltin(ctx: BBContext) {
|
||||
ctx.body = Object.values(permissions.getBuiltinPermissions())
|
||||
}
|
||||
|
||||
exports.fetchLevels = function (ctx) {
|
||||
export function fetchLevels(ctx: BBContext) {
|
||||
// for now only provide the read/write perms externally
|
||||
ctx.body = SUPPORTED_LEVELS
|
||||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
const roles = await getAllDBRoles(db)
|
||||
let permissions = {}
|
||||
export async function fetch(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const dbRoles: Role[] = await getAllDBRoles(db)
|
||||
let permissions: any = {}
|
||||
// create an object with structure role ID -> resource ID -> level
|
||||
for (let role of roles) {
|
||||
for (let role of dbRoles) {
|
||||
if (!role.permissions) {
|
||||
continue
|
||||
}
|
||||
const roleId = getExternalRoleID(role._id)
|
||||
const roleId = roles.getExternalRoleID(role._id)
|
||||
if (!roleId) {
|
||||
ctx.throw(400, "Unable to retrieve role")
|
||||
}
|
||||
for (let [resource, levelArr] of Object.entries(role.permissions)) {
|
||||
const levels = Array.isArray(levelArr) ? [levelArr] : levelArr
|
||||
const perms = {}
|
||||
levels.forEach(level => (perms[level] = roleId))
|
||||
const levels: string[] = Array.isArray(levelArr) ? levelArr : [levelArr]
|
||||
const perms: Record<string, string> = {}
|
||||
levels.forEach(level => (perms[level] = roleId!))
|
||||
permissions[resource] = perms
|
||||
}
|
||||
}
|
||||
// apply the base permissions
|
||||
const finalPermissions = {}
|
||||
const finalPermissions: Record<string, Record<string, string>> = {}
|
||||
for (let [resource, permission] of Object.entries(permissions)) {
|
||||
const basePerms = getBasePermissions(resource)
|
||||
finalPermissions[resource] = Object.assign(basePerms, permission)
|
||||
|
@ -132,33 +132,36 @@ exports.fetch = async function (ctx) {
|
|||
ctx.body = finalPermissions
|
||||
}
|
||||
|
||||
exports.getResourcePerms = async function (ctx) {
|
||||
export async function getResourcePerms(ctx: BBContext) {
|
||||
const resourceId = ctx.params.resourceId
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const body = await db.allDocs(
|
||||
getRoleParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
const roles = body.rows.map(row => row.doc)
|
||||
let permissions = {}
|
||||
const rolesList = body.rows.map(row => row.doc)
|
||||
let permissions: Record<string, string> = {}
|
||||
for (let level of SUPPORTED_LEVELS) {
|
||||
// update the various roleIds in the resource permissions
|
||||
for (let role of roles) {
|
||||
const rolePerms = checkForRoleResourceArray(role.permissions, resourceId)
|
||||
for (let role of rolesList) {
|
||||
const rolePerms = roles.checkForRoleResourceArray(
|
||||
role.permissions,
|
||||
resourceId
|
||||
)
|
||||
if (
|
||||
rolePerms &&
|
||||
rolePerms[resourceId] &&
|
||||
rolePerms[resourceId].indexOf(level) !== -1
|
||||
) {
|
||||
permissions[level] = getExternalRoleID(role._id)
|
||||
permissions[level] = roles.getExternalRoleID(role._id)!
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.body = Object.assign(getBasePermissions(resourceId), permissions)
|
||||
}
|
||||
|
||||
exports.addPermission = async function (ctx) {
|
||||
export async function addPermission(ctx: BBContext) {
|
||||
ctx.body = await updatePermissionOnRole(
|
||||
ctx.appId,
|
||||
ctx.params,
|
||||
|
@ -166,7 +169,7 @@ exports.addPermission = async function (ctx) {
|
|||
)
|
||||
}
|
||||
|
||||
exports.removePermission = async function (ctx) {
|
||||
export async function removePermission(ctx: BBContext) {
|
||||
ctx.body = await updatePermissionOnRole(
|
||||
ctx.appId,
|
||||
ctx.params,
|
|
@ -1,6 +1,5 @@
|
|||
import { npmUpload, urlUpload, githubUpload, fileUpload } from "./uploaders"
|
||||
import { getGlobalDB } from "@budibase/backend-core/tenancy"
|
||||
import { validate } from "@budibase/backend-core/plugins"
|
||||
import { plugins as pluginCore, tenancy } from "@budibase/backend-core"
|
||||
import { PluginType, FileType, PluginSource } from "@budibase/types"
|
||||
import env from "../../../environment"
|
||||
import { ClientAppSocket } from "../../../websocket"
|
||||
|
@ -8,7 +7,7 @@ import { db as dbCore } from "@budibase/backend-core"
|
|||
import { plugins } from "@budibase/pro"
|
||||
|
||||
export async function getPlugins(type?: PluginType) {
|
||||
const db = getGlobalDB()
|
||||
const db = tenancy.getGlobalDB()
|
||||
const response = await db.allDocs(
|
||||
dbCore.getPluginParams(null, {
|
||||
include_docs: true,
|
||||
|
@ -76,7 +75,7 @@ export async function create(ctx: any) {
|
|||
break
|
||||
}
|
||||
|
||||
validate(metadata?.schema)
|
||||
pluginCore.validate(metadata?.schema)
|
||||
|
||||
// Only allow components in cloud
|
||||
if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
|
||||
|
@ -121,7 +120,7 @@ export async function processUploadedPlugin(
|
|||
source?: PluginSource
|
||||
) {
|
||||
const { metadata, directory } = await fileUpload(plugin)
|
||||
validate(metadata?.schema)
|
||||
pluginCore.validate(metadata?.schema)
|
||||
|
||||
// Only allow components in cloud
|
||||
if (!env.SELF_HOSTED && metadata?.schema?.type !== PluginType.COMPONENT) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { search as stringSearch, addRev } from "./utils"
|
||||
import { default as controller } from "../table"
|
||||
import { Table } from "../../../definitions/common"
|
||||
import * as controller from "../table"
|
||||
import { Table } from "@budibase/types"
|
||||
|
||||
function fixTable(table: Table, params: any) {
|
||||
if (!params || !table) {
|
||||
|
|
|
@ -5,8 +5,7 @@ import { OpenAPI2 } from "./sources/openapi2"
|
|||
import { OpenAPI3 } from "./sources/openapi3"
|
||||
import { Curl } from "./sources/curl"
|
||||
// @ts-ignore
|
||||
import { getAppDB } from "@budibase/backend-core/context"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import { events, context } from "@budibase/backend-core"
|
||||
import { Datasource, Query } from "@budibase/types"
|
||||
|
||||
interface ImportResult {
|
||||
|
@ -59,7 +58,7 @@ export class RestImporter {
|
|||
})
|
||||
|
||||
// persist queries
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const response = await db.bulkDocs(queries)
|
||||
|
||||
// create index to seperate queries and errors
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const { joiValidator } = require("@budibase/backend-core/auth")
|
||||
const Joi = require("joi")
|
||||
import { auth } from "@budibase/backend-core"
|
||||
import Joi from "joi"
|
||||
|
||||
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
||||
|
||||
exports.queryValidation = () => {
|
||||
export function queryValidation() {
|
||||
return Joi.object({
|
||||
_id: Joi.string(),
|
||||
_rev: Joi.string(),
|
||||
|
@ -25,14 +25,14 @@ exports.queryValidation = () => {
|
|||
}).unknown(true)
|
||||
}
|
||||
|
||||
exports.generateQueryValidation = () => {
|
||||
export function generateQueryValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(exports.queryValidation())
|
||||
return auth.joiValidator.body(queryValidation())
|
||||
}
|
||||
|
||||
exports.generateQueryPreviewValidation = () => {
|
||||
export function generateQueryPreviewValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(Joi.object({
|
||||
return auth.joiValidator.body(Joi.object({
|
||||
_id: OPTIONAL_STRING,
|
||||
_rev: OPTIONAL_STRING,
|
||||
readable: Joi.boolean().optional(),
|
|
@ -1,23 +1,21 @@
|
|||
const {
|
||||
Role,
|
||||
getRole,
|
||||
isBuiltin,
|
||||
getAllRoles,
|
||||
} = require("@budibase/backend-core/roles")
|
||||
const {
|
||||
import { roles, context, events } from "@budibase/backend-core"
|
||||
import {
|
||||
generateRoleID,
|
||||
getUserMetadataParams,
|
||||
InternalTables,
|
||||
} = require("../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
} from "../../db/utils"
|
||||
import { BBContext, Database } from "@budibase/types"
|
||||
|
||||
const UpdateRolesOptions = {
|
||||
CREATED: "created",
|
||||
REMOVED: "removed",
|
||||
}
|
||||
|
||||
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
||||
async function updateRolesOnUserTable(
|
||||
db: Database,
|
||||
roleId: string,
|
||||
updateOption: string
|
||||
) {
|
||||
const table = await db.get(InternalTables.USER_METADATA)
|
||||
const schema = table.schema
|
||||
const remove = updateOption === UpdateRolesOptions.REMOVED
|
||||
|
@ -40,27 +38,25 @@ async function updateRolesOnUserTable(db, roleId, updateOption) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
ctx.body = await getAllRoles()
|
||||
export async function fetch(ctx: BBContext) {
|
||||
ctx.body = await roles.getAllRoles()
|
||||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
ctx.body = await getRole(ctx.params.roleId)
|
||||
export async function find(ctx: BBContext) {
|
||||
ctx.body = await roles.getRole(ctx.params.roleId)
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function save(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let { _id, name, inherits, permissionId } = ctx.request.body
|
||||
let isCreate = false
|
||||
if (!_id) {
|
||||
_id = generateRoleID()
|
||||
isCreate = true
|
||||
} else if (isBuiltin(_id)) {
|
||||
} else if (roles.isBuiltin(_id)) {
|
||||
ctx.throw(400, "Cannot update builtin roles.")
|
||||
}
|
||||
const role = new Role(_id, name)
|
||||
.addPermission(permissionId)
|
||||
.addInheritance(inherits)
|
||||
const role = new roles.Role(_id, name, permissionId).addInheritance(inherits)
|
||||
if (ctx.request.body._rev) {
|
||||
role._rev = ctx.request.body._rev
|
||||
}
|
||||
|
@ -76,17 +72,17 @@ exports.save = async function (ctx) {
|
|||
ctx.message = `Role '${role.name}' created successfully.`
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const roleId = ctx.params.roleId
|
||||
const role = await db.get(roleId)
|
||||
if (isBuiltin(roleId)) {
|
||||
if (roles.isBuiltin(roleId)) {
|
||||
ctx.throw(400, "Cannot delete builtin role.")
|
||||
}
|
||||
// first check no users actively attached to role
|
||||
const users = (
|
||||
await db.allDocs(
|
||||
getUserMetadataParams(null, {
|
||||
getUserMetadataParams(undefined, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
|
@ -1,40 +1,41 @@
|
|||
const { getRoutingInfo } = require("../../utilities/routing")
|
||||
const {
|
||||
getUserRoleHierarchy,
|
||||
BUILTIN_ROLE_IDS,
|
||||
} = require("@budibase/backend-core/roles")
|
||||
import { getRoutingInfo } from "../../utilities/routing"
|
||||
import { roles } from "@budibase/backend-core"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
const URL_SEPARATOR = "/"
|
||||
|
||||
function Routing() {
|
||||
this.json = {}
|
||||
}
|
||||
|
||||
Routing.prototype.getTopLevel = function (fullpath) {
|
||||
if (fullpath.charAt(0) !== URL_SEPARATOR) {
|
||||
fullpath = URL_SEPARATOR + fullpath
|
||||
class Routing {
|
||||
json: any
|
||||
constructor() {
|
||||
this.json = {}
|
||||
}
|
||||
// replace the first value with the home route
|
||||
return URL_SEPARATOR + fullpath.split(URL_SEPARATOR)[1]
|
||||
}
|
||||
|
||||
Routing.prototype.getScreensProp = function (fullpath) {
|
||||
const topLevel = this.getTopLevel(fullpath)
|
||||
if (!this.json[topLevel]) {
|
||||
this.json[topLevel] = {
|
||||
subpaths: {},
|
||||
getTopLevel(fullpath: string) {
|
||||
if (fullpath.charAt(0) !== URL_SEPARATOR) {
|
||||
fullpath = URL_SEPARATOR + fullpath
|
||||
}
|
||||
// replace the first value with the home route
|
||||
return URL_SEPARATOR + fullpath.split(URL_SEPARATOR)[1]
|
||||
}
|
||||
if (!this.json[topLevel].subpaths[fullpath]) {
|
||||
this.json[topLevel].subpaths[fullpath] = {
|
||||
screens: {},
|
||||
}
|
||||
}
|
||||
return this.json[topLevel].subpaths[fullpath].screens
|
||||
}
|
||||
|
||||
Routing.prototype.addScreenId = function (fullpath, roleId, screenId) {
|
||||
this.getScreensProp(fullpath)[roleId] = screenId
|
||||
getScreensProp(fullpath: string) {
|
||||
const topLevel = this.getTopLevel(fullpath)
|
||||
if (!this.json[topLevel]) {
|
||||
this.json[topLevel] = {
|
||||
subpaths: {},
|
||||
}
|
||||
}
|
||||
if (!this.json[topLevel].subpaths[fullpath]) {
|
||||
this.json[topLevel].subpaths[fullpath] = {
|
||||
screens: {},
|
||||
}
|
||||
}
|
||||
return this.json[topLevel].subpaths[fullpath].screens
|
||||
}
|
||||
|
||||
addScreenId(fullpath: string, roleId: string, screenId: string) {
|
||||
this.getScreensProp(fullpath)[roleId] = screenId
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,26 +56,28 @@ async function getRoutingStructure() {
|
|||
return { routes: routing.json }
|
||||
}
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
export async function fetch(ctx: BBContext) {
|
||||
ctx.body = await getRoutingStructure()
|
||||
}
|
||||
|
||||
exports.clientFetch = async ctx => {
|
||||
export async function clientFetch(ctx: BBContext) {
|
||||
const routing = await getRoutingStructure()
|
||||
let roleId = ctx.user.role._id
|
||||
const roleIds = await getUserRoleHierarchy(roleId)
|
||||
for (let topLevel of Object.values(routing.routes)) {
|
||||
let roleId = ctx.user?.role?._id
|
||||
const roleIds = (await roles.getUserRoleHierarchy(roleId, {
|
||||
idOnly: true,
|
||||
})) as string[]
|
||||
for (let topLevel of Object.values(routing.routes) as any) {
|
||||
for (let subpathKey of Object.keys(topLevel.subpaths)) {
|
||||
let found = false
|
||||
const subpath = topLevel.subpaths[subpathKey]
|
||||
const roleOptions = Object.keys(subpath.screens)
|
||||
if (roleOptions.length === 1 && !roleOptions[0]) {
|
||||
subpath.screenId = subpath.screens[roleOptions[0]]
|
||||
subpath.roleId = BUILTIN_ROLE_IDS.BASIC
|
||||
subpath.roleId = roles.BUILTIN_ROLE_IDS.BASIC
|
||||
found = true
|
||||
} else {
|
||||
for (let roleId of roleIds) {
|
||||
if (roleOptions.indexOf(roleId) !== -1) {
|
||||
if (roleId && roleOptions.indexOf(roleId) !== -1) {
|
||||
subpath.screenId = subpath.screens[roleId]
|
||||
subpath.roleId = roleId
|
||||
found = true
|
|
@ -27,12 +27,8 @@ import { breakExternalTableId, isSQL } from "../../../integrations/utils"
|
|||
import { processObjectSync } from "@budibase/string-templates"
|
||||
// @ts-ignore
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import {
|
||||
processFormulas,
|
||||
processDates,
|
||||
} from "../../../utilities/rowProcessor/utils"
|
||||
// @ts-ignore
|
||||
import { getAppDB } from "@budibase/backend-core/context"
|
||||
import { processFormulas, processDates } from "../../../utilities/rowProcessor"
|
||||
import { context } from "@budibase/backend-core"
|
||||
|
||||
interface ManyRelationship {
|
||||
tableId?: string
|
||||
|
@ -444,7 +440,7 @@ module External {
|
|||
// Process some additional data types
|
||||
let finalRowArray = Object.values(finalRows)
|
||||
finalRowArray = processDates(table, finalRowArray)
|
||||
finalRowArray = processFormulas(table, finalRowArray)
|
||||
finalRowArray = processFormulas(table, finalRowArray) as Row[]
|
||||
|
||||
return finalRowArray.map((row: Row) =>
|
||||
this.squashRelationshipColumns(table, row, relationships)
|
||||
|
@ -673,7 +669,7 @@ module External {
|
|||
throw "Unable to run without a table name"
|
||||
}
|
||||
if (!this.datasource) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
this.datasource = await db.get(datasourceId)
|
||||
if (!this.datasource || !this.datasource.entities) {
|
||||
throw "No tables found, fetch tables before query."
|
||||
|
|
|
@ -9,7 +9,7 @@ const {
|
|||
breakRowIdField,
|
||||
} = require("../../../integrations/utils")
|
||||
const ExternalRequest = require("./ExternalRequest")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { context } = require("@budibase/backend-core")
|
||||
const exporters = require("../view/exporters")
|
||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
||||
|
||||
|
@ -166,7 +166,7 @@ exports.validate = async () => {
|
|||
|
||||
exports.exportRows = async ctx => {
|
||||
const { datasourceId } = breakExternalTableId(ctx.params.tableId)
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const format = ctx.query.format
|
||||
const { columns } = ctx.request.body
|
||||
const datasource = await db.get(datasourceId)
|
||||
|
@ -209,7 +209,7 @@ exports.fetchEnrichedRow = async ctx => {
|
|||
const id = ctx.params.rowId
|
||||
const tableId = ctx.params.tableId
|
||||
const { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
if (!datasource || !datasource.entities) {
|
||||
ctx.throw(400, "Datasource has not been configured for plus API.")
|
||||
|
|
|
@ -6,7 +6,6 @@ const {
|
|||
DocumentType,
|
||||
InternalTables,
|
||||
} = require("../../../db/utils")
|
||||
const { getDB } = require("@budibase/backend-core/db")
|
||||
const userController = require("../user")
|
||||
const {
|
||||
inputProcessing,
|
||||
|
@ -26,7 +25,7 @@ const {
|
|||
getFromMemoryDoc,
|
||||
} = require("../view/utils")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { context, db: dbCore } = require("@budibase/backend-core")
|
||||
const { finaliseRow, updateRelatedFormula } = require("./staticFormula")
|
||||
const exporters = require("../view/exporters")
|
||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
||||
|
@ -80,7 +79,7 @@ async function getRawTableData(ctx, db, tableId) {
|
|||
}
|
||||
|
||||
exports.patch = async ctx => {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const inputs = ctx.request.body
|
||||
const tableId = inputs.tableId
|
||||
const isUserTable = tableId === InternalTables.USER_METADATA
|
||||
|
@ -145,7 +144,7 @@ exports.patch = async ctx => {
|
|||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
let inputs = ctx.request.body
|
||||
inputs.tableId = ctx.params.tableId
|
||||
|
||||
|
@ -188,7 +187,7 @@ exports.fetchView = async ctx => {
|
|||
return exports.fetch(ctx)
|
||||
}
|
||||
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const { calculation, group, field } = ctx.query
|
||||
const viewInfo = await getView(db, viewName)
|
||||
let response
|
||||
|
@ -242,7 +241,7 @@ exports.fetchView = async ctx => {
|
|||
}
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
|
||||
const tableId = ctx.params.tableId
|
||||
let table = await db.get(tableId)
|
||||
|
@ -251,7 +250,7 @@ exports.fetch = async ctx => {
|
|||
}
|
||||
|
||||
exports.find = async ctx => {
|
||||
const db = getDB(ctx.appId)
|
||||
const db = dbCore.getDB(ctx.appId)
|
||||
const table = await db.get(ctx.params.tableId)
|
||||
let row = await findRow(ctx, ctx.params.tableId, ctx.params.rowId)
|
||||
row = await outputProcessing(table, row)
|
||||
|
@ -259,7 +258,7 @@ exports.find = async ctx => {
|
|||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const { _id } = ctx.request.body
|
||||
let row = await db.get(_id)
|
||||
let _rev = ctx.request.body._rev || row._rev
|
||||
|
@ -295,7 +294,7 @@ exports.destroy = async function (ctx) {
|
|||
}
|
||||
|
||||
exports.bulkDestroy = async ctx => {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const tableId = ctx.params.tableId
|
||||
const table = await db.get(tableId)
|
||||
let { rows } = ctx.request.body
|
||||
|
@ -338,7 +337,7 @@ exports.search = async ctx => {
|
|||
}
|
||||
|
||||
const { tableId } = ctx.params
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const { paginate, query, ...params } = ctx.request.body
|
||||
params.version = ctx.version
|
||||
params.tableId = tableId
|
||||
|
@ -371,7 +370,7 @@ exports.validate = async ctx => {
|
|||
}
|
||||
|
||||
exports.exportRows = async ctx => {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const table = await db.get(ctx.params.tableId)
|
||||
const rowIds = ctx.request.body.rows
|
||||
let format = ctx.query.format
|
||||
|
@ -408,7 +407,7 @@ exports.exportRows = async ctx => {
|
|||
}
|
||||
|
||||
exports.fetchEnrichedRow = async ctx => {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const tableId = ctx.params.tableId
|
||||
const rowId = ctx.params.rowId
|
||||
// need table to work out where links go in row
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
const { SearchIndexes } = require("../../../db/utils")
|
||||
const { removeKeyNumbering } = require("./utils")
|
||||
const fetch = require("node-fetch")
|
||||
const { getCouchInfo } = require("@budibase/backend-core/db")
|
||||
const { getAppId } = require("@budibase/backend-core/context")
|
||||
import { SearchIndexes } from "../../../db/utils"
|
||||
import { removeKeyNumbering } from "./utils"
|
||||
import fetch from "node-fetch"
|
||||
import { db as dbCore, context } from "@budibase/backend-core"
|
||||
import { SearchFilters, Row } from "@budibase/types"
|
||||
|
||||
type SearchParams = {
|
||||
tableId: string
|
||||
sort?: string
|
||||
sortOrder?: string
|
||||
sortType?: string
|
||||
limit?: number
|
||||
bookmark?: string
|
||||
version?: string
|
||||
rows?: Row[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to build lucene query URLs.
|
||||
* Optionally takes a base lucene query object.
|
||||
*/
|
||||
class QueryBuilder {
|
||||
constructor(base) {
|
||||
export class QueryBuilder {
|
||||
query: SearchFilters
|
||||
limit: number
|
||||
sort?: string
|
||||
bookmark?: string
|
||||
sortOrder: string
|
||||
sortType: string
|
||||
includeDocs: boolean
|
||||
version?: string
|
||||
|
||||
constructor(base?: SearchFilters) {
|
||||
this.query = {
|
||||
allOr: false,
|
||||
string: {},
|
||||
|
@ -29,49 +49,52 @@ class QueryBuilder {
|
|||
this.sortOrder = "ascending"
|
||||
this.sortType = "string"
|
||||
this.includeDocs = true
|
||||
this.version = null
|
||||
}
|
||||
|
||||
setVersion(version) {
|
||||
this.version = version
|
||||
setVersion(version?: string) {
|
||||
if (version != null) {
|
||||
this.version = version
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setTable(tableId) {
|
||||
this.query.equal.tableId = tableId
|
||||
setTable(tableId: string) {
|
||||
this.query.equal!.tableId = tableId
|
||||
return this
|
||||
}
|
||||
|
||||
setLimit(limit) {
|
||||
setLimit(limit?: number) {
|
||||
if (limit != null) {
|
||||
this.limit = limit
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setSort(sort) {
|
||||
setSort(sort?: string) {
|
||||
if (sort != null) {
|
||||
this.sort = sort
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setSortOrder(sortOrder) {
|
||||
setSortOrder(sortOrder?: string) {
|
||||
if (sortOrder != null) {
|
||||
this.sortOrder = sortOrder
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setSortType(sortType) {
|
||||
setSortType(sortType?: string) {
|
||||
if (sortType != null) {
|
||||
this.sortType = sortType
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setBookmark(bookmark) {
|
||||
this.bookmark = bookmark
|
||||
setBookmark(bookmark?: string) {
|
||||
if (bookmark != null) {
|
||||
this.bookmark = bookmark
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -80,61 +103,61 @@ class QueryBuilder {
|
|||
return this
|
||||
}
|
||||
|
||||
addString(key, partial) {
|
||||
this.query.string[key] = partial
|
||||
addString(key: string, partial: string) {
|
||||
this.query.string![key] = partial
|
||||
return this
|
||||
}
|
||||
|
||||
addFuzzy(key, fuzzy) {
|
||||
this.query.fuzzy[key] = fuzzy
|
||||
addFuzzy(key: string, fuzzy: string) {
|
||||
this.query.fuzzy![key] = fuzzy
|
||||
return this
|
||||
}
|
||||
|
||||
addRange(key, low, high) {
|
||||
this.query.range = {
|
||||
addRange(key: string, low: string | number, high: string | number) {
|
||||
this.query.range![key] = {
|
||||
low,
|
||||
high,
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
addEqual(key, value) {
|
||||
this.query.equal[key] = value
|
||||
addEqual(key: string, value: any) {
|
||||
this.query.equal![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addNotEqual(key, value) {
|
||||
this.query.notEqual[key] = value
|
||||
addNotEqual(key: string, value: any) {
|
||||
this.query.notEqual![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addEmpty(key, value) {
|
||||
this.query.empty[key] = value
|
||||
addEmpty(key: string, value: any) {
|
||||
this.query.empty![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addNotEmpty(key, value) {
|
||||
this.query.notEmpty[key] = value
|
||||
addNotEmpty(key: string, value: any) {
|
||||
this.query.notEmpty![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addOneOf(key, value) {
|
||||
this.query.oneOf[key] = value
|
||||
addOneOf(key: string, value: any) {
|
||||
this.query.oneOf![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addContains(key, value) {
|
||||
this.query.contains[key] = value
|
||||
addContains(key: string, value: any) {
|
||||
this.query.contains![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addNotContains(key, value) {
|
||||
this.query.notContains[key] = value
|
||||
addNotContains(key: string, value: any) {
|
||||
this.query.notContains![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
addContainsAny(key, value) {
|
||||
this.query.containsAny[key] = value
|
||||
addContainsAny(key: string, value: any) {
|
||||
this.query.containsAny![key] = value
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -145,7 +168,7 @@ class QueryBuilder {
|
|||
* @param options The preprocess options
|
||||
* @returns {string|*}
|
||||
*/
|
||||
preprocess(value, { escape, lowercase, wrap, type } = {}) {
|
||||
preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) {
|
||||
const hasVersion = !!this.version
|
||||
// Determine if type needs wrapped
|
||||
const originalType = typeof value
|
||||
|
@ -173,12 +196,12 @@ class QueryBuilder {
|
|||
let query = allOr ? "" : "*:*"
|
||||
const allPreProcessingOpts = { escape: true, lowercase: true, wrap: true }
|
||||
let tableId
|
||||
if (this.query.equal.tableId) {
|
||||
tableId = this.query.equal.tableId
|
||||
delete this.query.equal.tableId
|
||||
if (this.query.equal!.tableId) {
|
||||
tableId = this.query.equal!.tableId
|
||||
delete this.query.equal!.tableId
|
||||
}
|
||||
|
||||
const equal = (key, value) => {
|
||||
const equal = (key: string, value: any) => {
|
||||
// 0 evaluates to false, which means we would return all rows if we don't check it
|
||||
if (!value && value !== 0) {
|
||||
return null
|
||||
|
@ -186,7 +209,7 @@ class QueryBuilder {
|
|||
return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
||||
}
|
||||
|
||||
const contains = (key, value, mode = "AND") => {
|
||||
const contains = (key: string, value: any, mode = "AND") => {
|
||||
if (Array.isArray(value) && value.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
@ -202,16 +225,17 @@ class QueryBuilder {
|
|||
return `${key}:(${statement})`
|
||||
}
|
||||
|
||||
const notContains = (key, value) => {
|
||||
const notContains = (key: string, value: any) => {
|
||||
// @ts-ignore
|
||||
const allPrefix = allOr === "" ? "*:* AND" : ""
|
||||
return allPrefix + "NOT " + contains(key, value)
|
||||
}
|
||||
|
||||
const containsAny = (key, value) => {
|
||||
const containsAny = (key: string, value: any) => {
|
||||
return contains(key, value, "OR")
|
||||
}
|
||||
|
||||
const oneOf = (key, value) => {
|
||||
const oneOf = (key: string, value: any) => {
|
||||
if (!Array.isArray(value)) {
|
||||
if (typeof value === "string") {
|
||||
value = value.split(",")
|
||||
|
@ -229,7 +253,7 @@ class QueryBuilder {
|
|||
return `${key}:(${orStatement})`
|
||||
}
|
||||
|
||||
function build(structure, queryFn) {
|
||||
function build(structure: any, queryFn: any) {
|
||||
for (let [key, value] of Object.entries(structure)) {
|
||||
// check for new format - remove numbering if needed
|
||||
key = removeKeyNumbering(key)
|
||||
|
@ -249,7 +273,7 @@ class QueryBuilder {
|
|||
|
||||
// Construct the actual lucene search query string from JSON structure
|
||||
if (this.query.string) {
|
||||
build(this.query.string, (key, value) => {
|
||||
build(this.query.string, (key: string, value: any) => {
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
@ -262,7 +286,7 @@ class QueryBuilder {
|
|||
})
|
||||
}
|
||||
if (this.query.range) {
|
||||
build(this.query.range, (key, value) => {
|
||||
build(this.query.range, (key: string, value: any) => {
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
@ -278,7 +302,7 @@ class QueryBuilder {
|
|||
})
|
||||
}
|
||||
if (this.query.fuzzy) {
|
||||
build(this.query.fuzzy, (key, value) => {
|
||||
build(this.query.fuzzy, (key: string, value: any) => {
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
@ -294,7 +318,7 @@ class QueryBuilder {
|
|||
build(this.query.equal, equal)
|
||||
}
|
||||
if (this.query.notEqual) {
|
||||
build(this.query.notEqual, (key, value) => {
|
||||
build(this.query.notEqual, (key: string, value: any) => {
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
@ -302,10 +326,10 @@ class QueryBuilder {
|
|||
})
|
||||
}
|
||||
if (this.query.empty) {
|
||||
build(this.query.empty, key => `!${key}:["" TO *]`)
|
||||
build(this.query.empty, (key: string) => `!${key}:["" TO *]`)
|
||||
}
|
||||
if (this.query.notEmpty) {
|
||||
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
||||
build(this.query.notEmpty, (key: string) => `${key}:["" TO *]`)
|
||||
}
|
||||
if (this.query.oneOf) {
|
||||
build(this.query.oneOf, oneOf)
|
||||
|
@ -329,7 +353,7 @@ class QueryBuilder {
|
|||
}
|
||||
|
||||
buildSearchBody() {
|
||||
let body = {
|
||||
let body: any = {
|
||||
q: this.buildSearchQuery(),
|
||||
limit: Math.min(this.limit, 200),
|
||||
include_docs: this.includeDocs,
|
||||
|
@ -346,17 +370,14 @@ class QueryBuilder {
|
|||
}
|
||||
|
||||
async run() {
|
||||
const appId = getAppId()
|
||||
const { url, cookie } = getCouchInfo()
|
||||
const appId = context.getAppId()
|
||||
const { url, cookie } = dbCore.getCouchInfo()
|
||||
const fullPath = `${url}/${appId}/_design/database/_search/${SearchIndexes.ROWS}`
|
||||
const body = this.buildSearchBody()
|
||||
return await runQuery(fullPath, body, cookie)
|
||||
}
|
||||
}
|
||||
|
||||
// exported for unit testing
|
||||
exports.QueryBuilder = QueryBuilder
|
||||
|
||||
/**
|
||||
* Executes a lucene search query.
|
||||
* @param url The query URL
|
||||
|
@ -364,7 +385,7 @@ exports.QueryBuilder = QueryBuilder
|
|||
* @param cookie The auth cookie for CouchDB
|
||||
* @returns {Promise<{rows: []}>}
|
||||
*/
|
||||
const runQuery = async (url, body, cookie) => {
|
||||
const runQuery = async (url: string, body: any, cookie: string) => {
|
||||
const response = await fetch(url, {
|
||||
body: JSON.stringify(body),
|
||||
method: "POST",
|
||||
|
@ -374,11 +395,11 @@ const runQuery = async (url, body, cookie) => {
|
|||
})
|
||||
const json = await response.json()
|
||||
|
||||
let output = {
|
||||
let output: any = {
|
||||
rows: [],
|
||||
}
|
||||
if (json.rows != null && json.rows.length > 0) {
|
||||
output.rows = json.rows.map(row => row.doc)
|
||||
output.rows = json.rows.map((row: any) => row.doc)
|
||||
}
|
||||
if (json.bookmark) {
|
||||
output.bookmark = json.bookmark
|
||||
|
@ -402,7 +423,7 @@ const runQuery = async (url, body, cookie) => {
|
|||
* rows {array|null} Current results in the recursive search
|
||||
* @returns {Promise<*[]|*>}
|
||||
*/
|
||||
const recursiveSearch = async (query, params) => {
|
||||
async function recursiveSearch(query: any, params: any): Promise<any> {
|
||||
const bookmark = params.bookmark
|
||||
const rows = params.rows || []
|
||||
if (rows.length >= params.limit) {
|
||||
|
@ -450,7 +471,10 @@ const recursiveSearch = async (query, params) => {
|
|||
* bookmark {string} The bookmark to resume from
|
||||
* @returns {Promise<{hasNextPage: boolean, rows: *[]}>}
|
||||
*/
|
||||
exports.paginatedSearch = async (query, params) => {
|
||||
export async function paginatedSearch(
|
||||
query: SearchFilters,
|
||||
params: SearchParams
|
||||
) {
|
||||
let limit = params.limit
|
||||
if (limit == null || isNaN(limit) || limit < 0) {
|
||||
limit = 50
|
||||
|
@ -496,7 +520,7 @@ exports.paginatedSearch = async (query, params) => {
|
|||
* limit {number} The desired number of results
|
||||
* @returns {Promise<{rows: *}>}
|
||||
*/
|
||||
exports.fullSearch = async (query, params) => {
|
||||
export async function fullSearch(query: SearchFilters, params: SearchParams) {
|
||||
let limit = params.limit
|
||||
if (limit == null || isNaN(limit) || limit < 0) {
|
||||
limit = 1000
|
|
@ -1,13 +1,14 @@
|
|||
const { getRowParams } = require("../../../db/utils")
|
||||
const {
|
||||
import { getRowParams } from "../../../db/utils"
|
||||
import {
|
||||
outputProcessing,
|
||||
processAutoColumn,
|
||||
processFormulas,
|
||||
} = require("../../../utilities/rowProcessor")
|
||||
const { FieldTypes, FormulaTypes } = require("../../../constants")
|
||||
} from "../../../utilities/rowProcessor"
|
||||
import { FieldTypes, FormulaTypes } from "../../../constants"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { Table, Row } from "@budibase/types"
|
||||
const { isEqual } = require("lodash")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
|
||||
/**
|
||||
* This function runs through a list of enriched rows, looks at the rows which
|
||||
|
@ -15,22 +16,22 @@ const { getAppDB } = require("@budibase/backend-core/context")
|
|||
* updated.
|
||||
* NOTE: this will only for affect static formulas.
|
||||
*/
|
||||
exports.updateRelatedFormula = async (table, enrichedRows) => {
|
||||
const db = getAppDB()
|
||||
exports.updateRelatedFormula = async (table: Table, enrichedRows: Row[]) => {
|
||||
const db = context.getAppDB()
|
||||
// no formula to update, we're done
|
||||
if (!table.relatedFormula) {
|
||||
return
|
||||
}
|
||||
let promises = []
|
||||
let promises: Promise<any>[] = []
|
||||
for (let enrichedRow of Array.isArray(enrichedRows)
|
||||
? enrichedRows
|
||||
: [enrichedRows]) {
|
||||
// the related rows by tableId
|
||||
let relatedRows = {}
|
||||
let relatedRows: Record<string, Row[]> = {}
|
||||
for (let [key, field] of Object.entries(enrichedRow)) {
|
||||
const columnDefinition = table.schema[key]
|
||||
if (columnDefinition && columnDefinition.type === FieldTypes.LINK) {
|
||||
const relatedTableId = columnDefinition.tableId
|
||||
const relatedTableId = columnDefinition.tableId!
|
||||
if (!relatedRows[relatedTableId]) {
|
||||
relatedRows[relatedTableId] = []
|
||||
}
|
||||
|
@ -38,7 +39,7 @@ exports.updateRelatedFormula = async (table, enrichedRows) => {
|
|||
}
|
||||
}
|
||||
for (let tableId of table.relatedFormula) {
|
||||
let relatedTable
|
||||
let relatedTable: Table
|
||||
try {
|
||||
// no rows to update, skip
|
||||
if (!relatedRows[tableId] || relatedRows[tableId].length === 0) {
|
||||
|
@ -48,7 +49,7 @@ exports.updateRelatedFormula = async (table, enrichedRows) => {
|
|||
} catch (err) {
|
||||
// no error scenario, table doesn't seem to exist anymore, ignore
|
||||
}
|
||||
for (let column of Object.values(relatedTable.schema)) {
|
||||
for (let column of Object.values(relatedTable!.schema)) {
|
||||
// needs updated in related rows
|
||||
if (
|
||||
column.type === FieldTypes.FORMULA &&
|
||||
|
@ -57,7 +58,7 @@ exports.updateRelatedFormula = async (table, enrichedRows) => {
|
|||
// re-enrich rows for all the related, don't update the related formula for them
|
||||
promises = promises.concat(
|
||||
relatedRows[tableId].map(related =>
|
||||
exports.finaliseRow(relatedTable, related, {
|
||||
finaliseRow(relatedTable, related, {
|
||||
updateFormula: false,
|
||||
})
|
||||
)
|
||||
|
@ -70,8 +71,8 @@ exports.updateRelatedFormula = async (table, enrichedRows) => {
|
|||
await Promise.all(promises)
|
||||
}
|
||||
|
||||
exports.updateAllFormulasInTable = async table => {
|
||||
const db = getAppDB()
|
||||
export async function updateAllFormulasInTable(table: Table) {
|
||||
const db = context.getAppDB()
|
||||
// start by getting the raw rows (which will be written back to DB after update)
|
||||
let rows = (
|
||||
await db.allDocs(
|
||||
|
@ -88,7 +89,9 @@ exports.updateAllFormulasInTable = async table => {
|
|||
const updatedRows = []
|
||||
for (let row of rows) {
|
||||
// find the enriched row, if found process the formulas
|
||||
const enrichedRow = enrichedRows.find(enriched => enriched._id === row._id)
|
||||
const enrichedRow = enrichedRows.find(
|
||||
(enriched: any) => enriched._id === row._id
|
||||
)
|
||||
if (enrichedRow) {
|
||||
const processed = processFormulas(table, cloneDeep(row), {
|
||||
dynamic: false,
|
||||
|
@ -109,12 +112,14 @@ exports.updateAllFormulasInTable = async table => {
|
|||
* row. The reason we need to return the enriched row is that the automation row created trigger
|
||||
* expects the row to be totally enriched/contain all relationships.
|
||||
*/
|
||||
exports.finaliseRow = async (
|
||||
table,
|
||||
row,
|
||||
{ oldTable, updateFormula } = { updateFormula: true }
|
||||
) => {
|
||||
const db = getAppDB()
|
||||
export async function finaliseRow(
|
||||
table: Table,
|
||||
row: Row,
|
||||
{ oldTable, updateFormula }: { oldTable?: Table; updateFormula: boolean } = {
|
||||
updateFormula: true,
|
||||
}
|
||||
) {
|
||||
const db = context.getAppDB()
|
||||
row.type = "row"
|
||||
// process the row before return, to include relationships
|
||||
let enrichedRow = await outputProcessing(table, cloneDeep(row), {
|
||||
|
@ -131,7 +136,7 @@ exports.finaliseRow = async (
|
|||
if (oldTable && !isEqual(oldTable, table)) {
|
||||
try {
|
||||
await db.put(table)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.status === 409) {
|
||||
const updatedTable = await db.get(table._id)
|
||||
let response = processAutoColumn(null, updatedTable, row, {
|
|
@ -1,33 +1,32 @@
|
|||
import { InternalTables } from "../../../db/utils"
|
||||
import * as userController from "../user"
|
||||
import { FieldTypes } from "../../../constants"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { makeExternalQuery } from "../../../integrations/base/query"
|
||||
import { BBContext, Row, Table } from "@budibase/types"
|
||||
export { removeKeyNumbering } from "../../../integrations/base/utils"
|
||||
const validateJs = require("validate.js")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { InternalTables } = require("../../../db/utils")
|
||||
const userController = require("../user")
|
||||
const { FieldTypes } = require("../../../constants")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { makeExternalQuery } = require("../../../integrations/base/query")
|
||||
const { removeKeyNumbering } = require("../../../integrations/base/utils")
|
||||
|
||||
validateJs.extend(validateJs.validators.datetime, {
|
||||
parse: function (value) {
|
||||
parse: function (value: string) {
|
||||
return new Date(value).getTime()
|
||||
},
|
||||
// Input is a unix timestamp
|
||||
format: function (value) {
|
||||
format: function (value: string) {
|
||||
return new Date(value).toISOString()
|
||||
},
|
||||
})
|
||||
|
||||
exports.removeKeyNumbering = removeKeyNumbering
|
||||
|
||||
exports.getDatasourceAndQuery = async json => {
|
||||
export async function getDatasourceAndQuery(json: any) {
|
||||
const datasourceId = json.endpoint.datasourceId
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
return makeExternalQuery(datasource, json)
|
||||
}
|
||||
|
||||
exports.findRow = async (ctx, tableId, rowId) => {
|
||||
const db = getAppDB()
|
||||
export async function findRow(ctx: BBContext, tableId: string, rowId: string) {
|
||||
const db = context.getAppDB()
|
||||
let row
|
||||
// TODO remove special user case in future
|
||||
if (tableId === InternalTables.USER_METADATA) {
|
||||
|
@ -45,12 +44,20 @@ exports.findRow = async (ctx, tableId, rowId) => {
|
|||
return row
|
||||
}
|
||||
|
||||
exports.validate = async ({ tableId, row, table }) => {
|
||||
export async function validate({
|
||||
tableId,
|
||||
row,
|
||||
table,
|
||||
}: {
|
||||
tableId?: string
|
||||
row: Row
|
||||
table: Table
|
||||
}) {
|
||||
if (!table) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
table = await db.get(tableId)
|
||||
}
|
||||
const errors = {}
|
||||
const errors: any = {}
|
||||
for (let fieldName of Object.keys(table.schema)) {
|
||||
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
||||
const type = table.schema[fieldName].type
|
||||
|
@ -70,7 +77,7 @@ exports.validate = async ({ tableId, row, table }) => {
|
|||
if (!Array.isArray(row[fieldName])) {
|
||||
row[fieldName] = row[fieldName].split(",")
|
||||
}
|
||||
row[fieldName].map(val => {
|
||||
row[fieldName].map((val: any) => {
|
||||
if (
|
||||
!constraints.inclusion.includes(val) &&
|
||||
constraints.inclusion.length !== 0
|
|
@ -7,9 +7,9 @@ import {
|
|||
roles,
|
||||
} from "@budibase/backend-core"
|
||||
import { updateAppPackage } from "./application"
|
||||
import { Plugin, ScreenProps } from "@budibase/types"
|
||||
import { Plugin, ScreenProps, BBContext } from "@budibase/types"
|
||||
|
||||
exports.fetch = async (ctx: any) => {
|
||||
export async function fetch(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
|
||||
const screens = (
|
||||
|
@ -20,13 +20,17 @@ exports.fetch = async (ctx: any) => {
|
|||
)
|
||||
).rows.map((el: any) => el.doc)
|
||||
|
||||
const roleId = ctx.user?.role?._id as string
|
||||
if (!roleId) {
|
||||
ctx.throw("Unable to retrieve users role ID.")
|
||||
}
|
||||
ctx.body = await new roles.AccessController().checkScreensAccess(
|
||||
screens,
|
||||
ctx.user.role._id
|
||||
roleId
|
||||
)
|
||||
}
|
||||
|
||||
exports.save = async (ctx: any) => {
|
||||
export async function save(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
let screen = ctx.request.body
|
||||
|
||||
|
@ -92,7 +96,7 @@ exports.save = async (ctx: any) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.destroy = async (ctx: any) => {
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const id = ctx.params.screenId
|
||||
const screen = await db.get(id)
|
||||
|
@ -106,7 +110,7 @@ exports.destroy = async (ctx: any) => {
|
|||
ctx.status = 200
|
||||
}
|
||||
|
||||
const findPlugins = (component: ScreenProps, foundPlugins: string[]) => {
|
||||
function findPlugins(component: ScreenProps, foundPlugins: string[]) {
|
||||
if (!component) {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
const ScriptRunner = require("../../utilities/scriptRunner")
|
||||
|
||||
exports.execute = async function (ctx) {
|
||||
const { script, context } = ctx.request.body
|
||||
const runner = new ScriptRunner(script, context)
|
||||
ctx.body = runner.execute()
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
ctx.throw(501, "Not currently implemented")
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import ScriptRunner from "../../utilities/scriptRunner"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
export async function execute(ctx: BBContext) {
|
||||
const { script, context } = ctx.request.body
|
||||
const runner = new ScriptRunner(script, context)
|
||||
ctx.body = runner.execute()
|
||||
}
|
||||
|
||||
export async function save(ctx: BBContext) {
|
||||
ctx.throw(501, "Not currently implemented")
|
||||
}
|
|
@ -17,13 +17,9 @@ const { clientLibraryPath } = require("../../../utilities")
|
|||
const { upload, deleteFiles } = require("../../../utilities/fileSystem")
|
||||
const { attachmentsRelativeURL } = require("../../../utilities")
|
||||
const { DocumentType } = require("../../../db/utils")
|
||||
const { getAppDB, getAppId } = require("@budibase/backend-core/context")
|
||||
const { setCookie, clearCookie } = require("@budibase/backend-core/utils")
|
||||
const { context, objectStore, utils } = require("@budibase/backend-core")
|
||||
const AWS = require("aws-sdk")
|
||||
const fs = require("fs")
|
||||
const {
|
||||
downloadTarballDirect,
|
||||
} = require("../../../utilities/fileSystem/utilities")
|
||||
|
||||
async function prepareUpload({ s3Key, bucket, metadata, file }: any) {
|
||||
const response = await upload({
|
||||
|
@ -48,7 +44,7 @@ export const toggleBetaUiFeature = async function (ctx: any) {
|
|||
const cookieName = `beta:${ctx.params.feature}`
|
||||
|
||||
if (ctx.cookies.get(cookieName)) {
|
||||
clearCookie(ctx, cookieName)
|
||||
utils.clearCookie(ctx, cookieName)
|
||||
ctx.body = {
|
||||
message: `${ctx.params.feature} disabled`,
|
||||
}
|
||||
|
@ -61,11 +57,11 @@ export const toggleBetaUiFeature = async function (ctx: any) {
|
|||
if (!fs.existsSync(builderPath)) {
|
||||
fs.mkdirSync(builderPath)
|
||||
}
|
||||
await downloadTarballDirect(
|
||||
await objectStore.downloadTarballDirect(
|
||||
"https://cdn.budi.live/beta:design_ui/new_ui.tar.gz",
|
||||
builderPath
|
||||
)
|
||||
setCookie(ctx, {}, cookieName)
|
||||
utils.setCookie(ctx, {}, cookieName)
|
||||
|
||||
ctx.body = {
|
||||
message: `${ctx.params.feature} enabled`,
|
||||
|
@ -103,9 +99,9 @@ export const deleteObjects = async function (ctx: any) {
|
|||
}
|
||||
|
||||
export const serveApp = async function (ctx: any) {
|
||||
const db = getAppDB({ skip_setup: true })
|
||||
const db = context.getAppDB({ skip_setup: true })
|
||||
const appInfo = await db.get(DocumentType.APP_METADATA)
|
||||
let appId = getAppId()
|
||||
let appId = context.getAppId()
|
||||
|
||||
if (!env.isJest()) {
|
||||
const App = require("./templates/BudibaseApp.svelte").default
|
||||
|
@ -134,11 +130,11 @@ export const serveApp = async function (ctx: any) {
|
|||
}
|
||||
|
||||
export const serveBuilderPreview = async function (ctx: any) {
|
||||
const db = getAppDB({ skip_setup: true })
|
||||
const db = context.getAppDB({ skip_setup: true })
|
||||
const appInfo = await db.get(DocumentType.APP_METADATA)
|
||||
|
||||
if (!env.isJest()) {
|
||||
let appId = getAppId()
|
||||
let appId = context.getAppId()
|
||||
const previewHbs = loadHandlebarsFile(`${__dirname}/templates/preview.hbs`)
|
||||
ctx.body = await processString(previewHbs, {
|
||||
clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
|
||||
|
@ -156,7 +152,7 @@ export const serveClientLibrary = async function (ctx: any) {
|
|||
}
|
||||
|
||||
export const getSignedUploadURL = async function (ctx: any) {
|
||||
const database = getAppDB()
|
||||
const database = context.getAppDB()
|
||||
|
||||
// Ensure datasource is valid
|
||||
let datasource
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
const { FieldTypes, FormulaTypes } = require("../../../constants")
|
||||
const { clearColumns } = require("./utils")
|
||||
const { doesContainStrings } = require("@budibase/string-templates")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const { isEqual, uniq } = require("lodash")
|
||||
const { updateAllFormulasInTable } = require("../row/staticFormula")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const sdk = require("../../../sdk")
|
||||
import { FieldTypes, FormulaTypes } from "../../../constants"
|
||||
import { clearColumns } from "./utils"
|
||||
import { doesContainStrings } from "@budibase/string-templates"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { isEqual, uniq } from "lodash"
|
||||
import { updateAllFormulasInTable } from "../row/staticFormula"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { FieldSchema, Table } from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
function isStaticFormula(column) {
|
||||
function isStaticFormula(column: FieldSchema) {
|
||||
return (
|
||||
column.type === FieldTypes.FORMULA &&
|
||||
column.formulaType === FormulaTypes.STATIC
|
||||
|
@ -18,8 +19,8 @@ function isStaticFormula(column) {
|
|||
* This retrieves the formula columns from a table schema that use a specified column name
|
||||
* in the formula.
|
||||
*/
|
||||
function getFormulaThatUseColumn(table, columnNames) {
|
||||
let formula = []
|
||||
function getFormulaThatUseColumn(table: Table, columnNames: string[] | string) {
|
||||
let formula: string[] = []
|
||||
columnNames = Array.isArray(columnNames) ? columnNames : [columnNames]
|
||||
for (let column of Object.values(table.schema)) {
|
||||
// not a static formula, or doesn't contain a relationship
|
||||
|
@ -38,7 +39,10 @@ function getFormulaThatUseColumn(table, columnNames) {
|
|||
* This functions checks for when a related table, column or related column is deleted, if any
|
||||
* tables need to have the formula column removed.
|
||||
*/
|
||||
async function checkIfFormulaNeedsCleared(table, { oldTable, deletion }) {
|
||||
async function checkIfFormulaNeedsCleared(
|
||||
table: Table,
|
||||
{ oldTable, deletion }: { oldTable?: Table; deletion?: boolean }
|
||||
) {
|
||||
// start by retrieving all tables, remove the current table from the list
|
||||
const tables = (await sdk.tables.getAllInternalTables()).filter(
|
||||
tbl => tbl._id !== table._id
|
||||
|
@ -49,11 +53,14 @@ async function checkIfFormulaNeedsCleared(table, { oldTable, deletion }) {
|
|||
)
|
||||
// remove any formula columns that used related columns
|
||||
for (let removed of removedColumns) {
|
||||
let tableToUse = table
|
||||
let tableToUse: Table | undefined = table
|
||||
// if relationship, get the related table
|
||||
if (removed.type === FieldTypes.LINK) {
|
||||
tableToUse = tables.find(table => table._id === removed.tableId)
|
||||
}
|
||||
if (!tableToUse) {
|
||||
continue
|
||||
}
|
||||
const columnsToDelete = getFormulaThatUseColumn(tableToUse, removed.name)
|
||||
if (columnsToDelete.length > 0) {
|
||||
await clearColumns(table, columnsToDelete)
|
||||
|
@ -71,11 +78,11 @@ async function checkIfFormulaNeedsCleared(table, { oldTable, deletion }) {
|
|||
// look to see if the column was used in a relationship formula,
|
||||
// relationships won't be used for this
|
||||
if (relatedTable && relatedColumns && removed.type !== FieldTypes.LINK) {
|
||||
let relatedFormulaToRemove = []
|
||||
let relatedFormulaToRemove: string[] = []
|
||||
for (let column of relatedColumns) {
|
||||
relatedFormulaToRemove = relatedFormulaToRemove.concat(
|
||||
getFormulaThatUseColumn(relatedTable, [
|
||||
column.fieldName,
|
||||
column.fieldName!,
|
||||
removed.name,
|
||||
])
|
||||
)
|
||||
|
@ -95,13 +102,14 @@ async function checkIfFormulaNeedsCleared(table, { oldTable, deletion }) {
|
|||
* specifically only for static formula.
|
||||
*/
|
||||
async function updateRelatedFormulaLinksOnTables(
|
||||
table,
|
||||
{ deletion } = { deletion: false }
|
||||
table: Table,
|
||||
{ deletion }: { deletion?: boolean } = {}
|
||||
) {
|
||||
const db = getAppDB()
|
||||
const tableId: string = table._id!
|
||||
const db = context.getAppDB()
|
||||
// start by retrieving all tables, remove the current table from the list
|
||||
const tables = (await sdk.tables.getAllInternalTables()).filter(
|
||||
tbl => tbl._id !== table._id
|
||||
tbl => tbl._id !== tableId
|
||||
)
|
||||
// clone the tables, so we can compare at end
|
||||
const initialTables = cloneDeep(tables)
|
||||
|
@ -114,7 +122,7 @@ async function updateRelatedFormulaLinksOnTables(
|
|||
if (!otherTable.relatedFormula) {
|
||||
continue
|
||||
}
|
||||
const index = otherTable.relatedFormula.indexOf(table._id)
|
||||
const index = otherTable.relatedFormula.indexOf(tableId)
|
||||
if (index !== -1) {
|
||||
otherTable.relatedFormula.splice(index, 1)
|
||||
}
|
||||
|
@ -133,11 +141,11 @@ async function updateRelatedFormulaLinksOnTables(
|
|||
if (
|
||||
relatedTable &&
|
||||
(!relatedTable.relatedFormula ||
|
||||
!relatedTable.relatedFormula.includes(table._id))
|
||||
!relatedTable.relatedFormula.includes(tableId))
|
||||
) {
|
||||
relatedTable.relatedFormula = relatedTable.relatedFormula
|
||||
? [...relatedTable.relatedFormula, table._id]
|
||||
: [table._id]
|
||||
? [...relatedTable.relatedFormula, tableId]
|
||||
: [tableId]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +158,10 @@ async function updateRelatedFormulaLinksOnTables(
|
|||
}
|
||||
}
|
||||
|
||||
async function checkIfFormulaUpdated(table, { oldTable }) {
|
||||
async function checkIfFormulaUpdated(
|
||||
table: Table,
|
||||
{ oldTable }: { oldTable?: Table }
|
||||
) {
|
||||
// look to see if any formula values have changed
|
||||
const shouldUpdate = Object.values(table.schema).find(
|
||||
column =>
|
||||
|
@ -165,7 +176,10 @@ async function checkIfFormulaUpdated(table, { oldTable }) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.runStaticFormulaChecks = async (table, { oldTable, deletion }) => {
|
||||
export async function runStaticFormulaChecks(
|
||||
table: Table,
|
||||
{ oldTable, deletion }: { oldTable?: Table; deletion?: boolean }
|
||||
) {
|
||||
await updateRelatedFormulaLinksOnTables(table, { deletion })
|
||||
await checkIfFormulaNeedsCleared(table, { oldTable, deletion })
|
||||
if (!deletion) {
|
|
@ -1,38 +1,47 @@
|
|||
const {
|
||||
import {
|
||||
buildExternalTableId,
|
||||
breakExternalTableId,
|
||||
} = require("../../../integrations/utils")
|
||||
const {
|
||||
} from "../../../integrations/utils"
|
||||
import {
|
||||
generateForeignKey,
|
||||
generateJunctionTableName,
|
||||
foreignKeyStructure,
|
||||
hasTypeChanged,
|
||||
} = require("./utils")
|
||||
const {
|
||||
} from "./utils"
|
||||
import {
|
||||
DataSourceOperation,
|
||||
FieldTypes,
|
||||
RelationshipTypes,
|
||||
} = require("../../../constants")
|
||||
const { makeExternalQuery } = require("../../../integrations/base/query")
|
||||
} from "../../../constants"
|
||||
import { makeExternalQuery } from "../../../integrations/base/query"
|
||||
import csvParser from "../../../utilities/csvParser"
|
||||
import { handleRequest } from "../row/external"
|
||||
import { events, context } from "@budibase/backend-core"
|
||||
import {
|
||||
Datasource,
|
||||
Table,
|
||||
QueryJson,
|
||||
Operation,
|
||||
RenameColumn,
|
||||
FieldSchema,
|
||||
BBContext,
|
||||
TableRequest,
|
||||
} from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const csvParser = require("../../../utilities/csvParser")
|
||||
const { handleRequest } = require("../row/external")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
const sdk = require("../../../sdk")
|
||||
|
||||
async function makeTableRequest(
|
||||
datasource,
|
||||
operation,
|
||||
table,
|
||||
tables,
|
||||
oldTable = null,
|
||||
renamed = null
|
||||
datasource: Datasource,
|
||||
operation: Operation,
|
||||
table: Table,
|
||||
tables: Record<string, Table>,
|
||||
oldTable?: Table,
|
||||
renamed?: RenameColumn
|
||||
) {
|
||||
const json = {
|
||||
const json: QueryJson = {
|
||||
endpoint: {
|
||||
datasourceId: datasource._id,
|
||||
entityId: table._id,
|
||||
datasourceId: datasource._id!,
|
||||
entityId: table._id!,
|
||||
operation,
|
||||
},
|
||||
meta: {
|
||||
|
@ -41,15 +50,19 @@ async function makeTableRequest(
|
|||
table,
|
||||
}
|
||||
if (oldTable) {
|
||||
json.meta.table = oldTable
|
||||
json.meta!.table = oldTable
|
||||
}
|
||||
if (renamed) {
|
||||
json.meta.renamed = renamed
|
||||
json.meta!.renamed = renamed
|
||||
}
|
||||
return makeExternalQuery(datasource, json)
|
||||
}
|
||||
|
||||
function cleanupRelationships(table, tables, oldTable = null) {
|
||||
function cleanupRelationships(
|
||||
table: Table,
|
||||
tables: Record<string, Table>,
|
||||
oldTable?: Table
|
||||
) {
|
||||
const tableToIterate = oldTable ? oldTable : table
|
||||
// clean up relationships in couch table schemas
|
||||
for (let [key, schema] of Object.entries(tableToIterate.schema)) {
|
||||
|
@ -78,7 +91,7 @@ function cleanupRelationships(table, tables, oldTable = null) {
|
|||
}
|
||||
}
|
||||
|
||||
function getDatasourceId(table) {
|
||||
function getDatasourceId(table: Table) {
|
||||
if (!table) {
|
||||
throw "No table supplied"
|
||||
}
|
||||
|
@ -88,7 +101,7 @@ function getDatasourceId(table) {
|
|||
return breakExternalTableId(table._id).datasourceId
|
||||
}
|
||||
|
||||
function otherRelationshipType(type) {
|
||||
function otherRelationshipType(type?: string) {
|
||||
if (type === RelationshipTypes.MANY_TO_MANY) {
|
||||
return RelationshipTypes.MANY_TO_MANY
|
||||
}
|
||||
|
@ -97,13 +110,21 @@ function otherRelationshipType(type) {
|
|||
: RelationshipTypes.ONE_TO_MANY
|
||||
}
|
||||
|
||||
function generateManyLinkSchema(datasource, column, table, relatedTable) {
|
||||
function generateManyLinkSchema(
|
||||
datasource: Datasource,
|
||||
column: FieldSchema,
|
||||
table: Table,
|
||||
relatedTable: Table
|
||||
): Table {
|
||||
if (!table.primary || !relatedTable.primary) {
|
||||
throw new Error("Unable to generate many link schema, no primary keys")
|
||||
}
|
||||
const primary = table.name + table.primary[0]
|
||||
const relatedPrimary = relatedTable.name + relatedTable.primary[0]
|
||||
const jcTblName = generateJunctionTableName(column, table, relatedTable)
|
||||
// first create the new table
|
||||
const junctionTable = {
|
||||
_id: buildExternalTableId(datasource._id, jcTblName),
|
||||
_id: buildExternalTableId(datasource._id!, jcTblName),
|
||||
name: jcTblName,
|
||||
primary: [primary, relatedPrimary],
|
||||
constrained: [primary, relatedPrimary],
|
||||
|
@ -125,7 +146,15 @@ function generateManyLinkSchema(datasource, column, table, relatedTable) {
|
|||
return junctionTable
|
||||
}
|
||||
|
||||
function generateLinkSchema(column, table, relatedTable, type) {
|
||||
function generateLinkSchema(
|
||||
column: FieldSchema,
|
||||
table: Table,
|
||||
relatedTable: Table,
|
||||
type: string
|
||||
) {
|
||||
if (!table.primary || !relatedTable.primary) {
|
||||
throw new Error("Unable to generate link schema, no primary keys")
|
||||
}
|
||||
const isOneSide = type === RelationshipTypes.ONE_TO_MANY
|
||||
const primary = isOneSide ? relatedTable.primary[0] : table.primary[0]
|
||||
// generate a foreign key
|
||||
|
@ -136,7 +165,12 @@ function generateLinkSchema(column, table, relatedTable, type) {
|
|||
return foreignKey
|
||||
}
|
||||
|
||||
function generateRelatedSchema(linkColumn, table, relatedTable, columnName) {
|
||||
function generateRelatedSchema(
|
||||
linkColumn: FieldSchema,
|
||||
table: Table,
|
||||
relatedTable: Table,
|
||||
columnName: string
|
||||
) {
|
||||
// generate column for other table
|
||||
const relatedSchema = cloneDeep(linkColumn)
|
||||
// swap them from the main link
|
||||
|
@ -159,21 +193,21 @@ function generateRelatedSchema(linkColumn, table, relatedTable, columnName) {
|
|||
table.schema[columnName] = relatedSchema
|
||||
}
|
||||
|
||||
function isRelationshipSetup(column) {
|
||||
function isRelationshipSetup(column: FieldSchema) {
|
||||
return column.foreignKey || column.through
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
const table = ctx.request.body
|
||||
const { _rename: renamed } = table
|
||||
export async function save(ctx: BBContext) {
|
||||
const table: TableRequest = ctx.request.body
|
||||
const renamed = table?._rename
|
||||
// can't do this right now
|
||||
delete table.dataImport
|
||||
const datasourceId = getDatasourceId(ctx.request.body)
|
||||
const datasourceId = getDatasourceId(ctx.request.body)!
|
||||
// table doesn't exist already, note that it is created
|
||||
if (!table._id) {
|
||||
table.created = true
|
||||
}
|
||||
let tableToSave = {
|
||||
let tableToSave: TableRequest = {
|
||||
type: "table",
|
||||
_id: buildExternalTableId(datasourceId, table.name),
|
||||
...table,
|
||||
|
@ -188,10 +222,10 @@ exports.save = async function (ctx) {
|
|||
ctx.throw(400, "A column type has changed.")
|
||||
}
|
||||
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
const oldTables = cloneDeep(datasource.entities)
|
||||
const tables = datasource.entities
|
||||
const tables: Record<string, Table> = datasource.entities
|
||||
|
||||
const extraTablesToUpdate = []
|
||||
|
||||
|
@ -203,8 +237,11 @@ exports.save = async function (ctx) {
|
|||
const relatedTable = Object.values(tables).find(
|
||||
table => table._id === schema.tableId
|
||||
)
|
||||
const relatedColumnName = schema.fieldName
|
||||
const relationType = schema.relationshipType
|
||||
if (!relatedTable) {
|
||||
continue
|
||||
}
|
||||
const relatedColumnName = schema.fieldName!
|
||||
const relationType = schema.relationshipType!
|
||||
if (relationType === RelationshipTypes.MANY_TO_MANY) {
|
||||
const junctionTable = generateManyLinkSchema(
|
||||
datasource,
|
||||
|
@ -244,9 +281,7 @@ exports.save = async function (ctx) {
|
|||
|
||||
cleanupRelationships(tableToSave, tables, oldTable)
|
||||
|
||||
const operation = oldTable
|
||||
? DataSourceOperation.UPDATE_TABLE
|
||||
: DataSourceOperation.CREATE_TABLE
|
||||
const operation = oldTable ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
||||
await makeTableRequest(
|
||||
datasource,
|
||||
operation,
|
||||
|
@ -258,9 +293,7 @@ exports.save = async function (ctx) {
|
|||
// update any extra tables (like foreign keys in other tables)
|
||||
for (let extraTable of extraTablesToUpdate) {
|
||||
const oldExtraTable = oldTables[extraTable.name]
|
||||
let op = oldExtraTable
|
||||
? DataSourceOperation.UPDATE_TABLE
|
||||
: DataSourceOperation.CREATE_TABLE
|
||||
let op = oldExtraTable ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
||||
await makeTableRequest(datasource, op, extraTable, tables, oldExtraTable)
|
||||
}
|
||||
|
||||
|
@ -280,18 +313,20 @@ exports.save = async function (ctx) {
|
|||
return tableToSave
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
const tableToDelete = await sdk.tables.getTable(ctx.params.tableId)
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const tableToDelete: TableRequest = await sdk.tables.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 = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const datasource = await db.get(datasourceId)
|
||||
const tables = datasource.entities
|
||||
|
||||
const operation = DataSourceOperation.DELETE_TABLE
|
||||
const operation = Operation.DELETE_TABLE
|
||||
await makeTableRequest(datasource, operation, tableToDelete, tables)
|
||||
|
||||
cleanupRelationships(tableToDelete, tables)
|
||||
|
@ -302,7 +337,7 @@ exports.destroy = async function (ctx) {
|
|||
return tableToDelete
|
||||
}
|
||||
|
||||
exports.bulkImport = async function (ctx) {
|
||||
export async function bulkImport(ctx: BBContext) {
|
||||
const table = await sdk.tables.getTable(ctx.params.tableId)
|
||||
const { dataImport } = ctx.request.body
|
||||
if (!dataImport || !dataImport.schema || !dataImport.csvString) {
|
|
@ -1,13 +1,13 @@
|
|||
const internal = require("./internal")
|
||||
const external = require("./external")
|
||||
const csvParser = require("../../../utilities/csvParser")
|
||||
const { isExternalTable, isSQL } = require("../../../integrations/utils")
|
||||
const { getDatasourceParams } = require("../../../db/utils")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
const sdk = require("../../../sdk")
|
||||
import * as internal from "./internal"
|
||||
import * as external from "./external"
|
||||
import csvParser from "../../../utilities/csvParser"
|
||||
import { isExternalTable, isSQL } from "../../../integrations/utils"
|
||||
import { getDatasourceParams } from "../../../db/utils"
|
||||
import { context, events } from "@budibase/backend-core"
|
||||
import { Table, BBContext } from "@budibase/types"
|
||||
import sdk from "../../../sdk"
|
||||
|
||||
function pickApi({ tableId, table }) {
|
||||
function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
|
||||
if (table && !tableId) {
|
||||
tableId = table._id
|
||||
}
|
||||
|
@ -20,8 +20,8 @@ function pickApi({ tableId, table }) {
|
|||
}
|
||||
|
||||
// covers both internal and external
|
||||
exports.fetch = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function fetch(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
|
||||
const internal = await sdk.tables.getAllInternalTables()
|
||||
|
||||
|
@ -34,7 +34,7 @@ exports.fetch = async function (ctx) {
|
|||
const external = externalTables.rows.flatMap(tableDoc => {
|
||||
let entities = tableDoc.doc.entities
|
||||
if (entities) {
|
||||
return Object.values(entities).map(entity => ({
|
||||
return Object.values(entities).map((entity: any) => ({
|
||||
...entity,
|
||||
type: "external",
|
||||
sourceId: tableDoc.doc._id,
|
||||
|
@ -48,12 +48,12 @@ exports.fetch = async function (ctx) {
|
|||
ctx.body = [...internal, ...external]
|
||||
}
|
||||
|
||||
exports.find = async function (ctx) {
|
||||
export async function find(ctx: BBContext) {
|
||||
const tableId = ctx.params.tableId
|
||||
ctx.body = await sdk.tables.getTable(tableId)
|
||||
}
|
||||
|
||||
exports.save = async function (ctx) {
|
||||
export async function save(ctx: BBContext) {
|
||||
const appId = ctx.appId
|
||||
const table = ctx.request.body
|
||||
const importFormat =
|
||||
|
@ -74,7 +74,7 @@ exports.save = async function (ctx) {
|
|||
ctx.body = savedTable
|
||||
}
|
||||
|
||||
exports.destroy = async function (ctx) {
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const appId = ctx.appId
|
||||
const tableId = ctx.params.tableId
|
||||
const deletedTable = await pickApi({ tableId }).destroy(ctx)
|
||||
|
@ -86,7 +86,7 @@ exports.destroy = async function (ctx) {
|
|||
ctx.body = { message: `Table ${tableId} deleted.` }
|
||||
}
|
||||
|
||||
exports.bulkImport = async function (ctx) {
|
||||
export async function bulkImport(ctx: BBContext) {
|
||||
const tableId = ctx.params.tableId
|
||||
await pickApi({ tableId }).bulkImport(ctx)
|
||||
// right now we don't trigger anything for bulk import because it
|
||||
|
@ -96,7 +96,7 @@ exports.bulkImport = async function (ctx) {
|
|||
ctx.body = { message: `Bulk rows created.` }
|
||||
}
|
||||
|
||||
exports.validateCSVSchema = async function (ctx) {
|
||||
export async function validateCSVSchema(ctx: BBContext) {
|
||||
// tableId being specified means its an import to an existing table
|
||||
const { csvString, schema = {}, tableId } = ctx.request.body
|
||||
let existingTable
|
|
@ -133,7 +133,7 @@ export async function save(ctx: any) {
|
|||
tableToSave._rev = result.rev
|
||||
}
|
||||
// has to run after, make sure it has _id
|
||||
await runStaticFormulaChecks(tableToSave, { oldTable, deletion: null })
|
||||
await runStaticFormulaChecks(tableToSave, { oldTable, deletion: false })
|
||||
return tableToSave
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,6 @@ export async function destroy(ctx: any) {
|
|||
|
||||
// has to run after, make sure it has _id
|
||||
await runStaticFormulaChecks(tableToDelete, {
|
||||
oldTable: null,
|
||||
deletion: true,
|
||||
})
|
||||
await cleanupAttachments(tableToDelete, {
|
||||
|
|
|
@ -13,28 +13,28 @@ import {
|
|||
} from "../../../constants"
|
||||
import { getViews, saveView } from "../view/utils"
|
||||
import viewTemplate from "../view/viewBuilder"
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import { events, context } from "@budibase/backend-core"
|
||||
import { Database } from "@budibase/types"
|
||||
|
||||
export async function clearColumns(table: any, columnNames: any) {
|
||||
const db = getAppDB()
|
||||
const db: Database = context.getAppDB()
|
||||
const rows = await db.allDocs(
|
||||
getRowParams(table._id, null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
return db.bulkDocs(
|
||||
return (await db.bulkDocs(
|
||||
rows.rows.map(({ doc }: any) => {
|
||||
columnNames.forEach((colName: any) => delete doc[colName])
|
||||
return doc
|
||||
})
|
||||
)
|
||||
)) as { id: string; _rev?: string }[]
|
||||
}
|
||||
|
||||
export async function checkForColumnUpdates(oldTable: any, updatedTable: any) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
let updatedRows = []
|
||||
const rename = updatedTable._rename
|
||||
let deletedColumns: any = []
|
||||
|
@ -133,7 +133,7 @@ export async function handleDataImport(user: any, table: any, dataImport: any) {
|
|||
return table
|
||||
}
|
||||
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
// Populate the table with rows imported from CSV in a bulk update
|
||||
const data = await transform({
|
||||
...dataImport,
|
||||
|
@ -150,7 +150,7 @@ export async function handleDataImport(user: any, table: any, dataImport: any) {
|
|||
}
|
||||
|
||||
export async function handleSearchIndexes(table: any) {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
// create relevant search indexes
|
||||
if (table.indexes && table.indexes.length > 0) {
|
||||
const currentIndexes = await db.getIndexes()
|
||||
|
@ -214,7 +214,7 @@ class TableSaveFunctions {
|
|||
rows: any
|
||||
|
||||
constructor({ user, oldTable, dataImport }: any) {
|
||||
this.db = getAppDB()
|
||||
this.db = context.getAppDB()
|
||||
this.user = user
|
||||
this.oldTable = oldTable
|
||||
this.dataImport = dataImport
|
||||
|
@ -338,7 +338,7 @@ export function generateJunctionTableName(
|
|||
return `jt_${table.name}_${relatedTable.name}_${column.name}_${column.fieldName}`
|
||||
}
|
||||
|
||||
export function foreignKeyStructure(keyName: any, meta = null) {
|
||||
export function foreignKeyStructure(keyName: any, meta?: any) {
|
||||
const structure: any = {
|
||||
type: FieldTypes.NUMBER,
|
||||
constraints: {},
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
const fetch = require("node-fetch")
|
||||
const { downloadTemplate } = require("../../utilities/fileSystem")
|
||||
const env = require("../../environment")
|
||||
import nodeFetch from "node-fetch"
|
||||
import { downloadTemplate as dlTemplate } from "../../utilities/fileSystem"
|
||||
import env from "../../environment"
|
||||
import { BBContext } from "@budibase/types"
|
||||
|
||||
// development flag, can be used to test against templates exported locally
|
||||
const DEFAULT_TEMPLATES_BUCKET =
|
||||
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
||||
|
||||
exports.fetch = async function (ctx) {
|
||||
export async function fetch(ctx: BBContext) {
|
||||
let type = env.TEMPLATE_REPOSITORY
|
||||
let response,
|
||||
error = false
|
||||
try {
|
||||
response = await fetch(`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`)
|
||||
response = await nodeFetch(
|
||||
`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`
|
||||
)
|
||||
if (response.status !== 200) {
|
||||
error = true
|
||||
}
|
||||
|
@ -29,10 +32,10 @@ exports.fetch = async function (ctx) {
|
|||
|
||||
// can't currently test this, have to ignore from coverage
|
||||
/* istanbul ignore next */
|
||||
exports.downloadTemplate = async function (ctx) {
|
||||
export async function downloadTemplate(ctx: BBContext) {
|
||||
const { type, name } = ctx.params
|
||||
|
||||
await downloadTemplate(type, name)
|
||||
await dlTemplate(type, name)
|
||||
|
||||
ctx.body = {
|
||||
message: `template ${type}:${name} downloaded successfully.`,
|
|
@ -1,23 +1,22 @@
|
|||
const {
|
||||
import {
|
||||
generateUserMetadataID,
|
||||
getUserMetadataParams,
|
||||
generateUserFlagID,
|
||||
} = require("../../db/utils")
|
||||
const { InternalTables } = require("../../db/utils")
|
||||
const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
|
||||
const { getFullUser } = require("../../utilities/users")
|
||||
const { isEqual } = require("lodash")
|
||||
const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles")
|
||||
const {
|
||||
getDevelopmentAppID,
|
||||
getProdAppIDs,
|
||||
dbExists,
|
||||
} = require("@budibase/backend-core/db")
|
||||
const { UserStatus } = require("@budibase/backend-core/constants")
|
||||
const { getAppDB, doInAppContext } = require("@budibase/backend-core/context")
|
||||
} from "../../db/utils"
|
||||
import { InternalTables } from "../../db/utils"
|
||||
import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global"
|
||||
import { getFullUser } from "../../utilities/users"
|
||||
import { isEqual } from "lodash"
|
||||
import {
|
||||
context,
|
||||
constants,
|
||||
roles as rolesCore,
|
||||
db as dbCore,
|
||||
} from "@budibase/backend-core"
|
||||
import { BBContext, User } from "@budibase/types"
|
||||
|
||||
async function rawMetadata() {
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
return (
|
||||
await db.allDocs(
|
||||
getUserMetadataParams(null, {
|
||||
|
@ -27,9 +26,9 @@ async function rawMetadata() {
|
|||
).rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
function combineMetadataAndUser(user, metadata) {
|
||||
function combineMetadataAndUser(user: any, metadata: any) {
|
||||
// skip users with no access
|
||||
if (user.roleId === BUILTIN_ROLE_IDS.PUBLIC) {
|
||||
if (user.roleId === rolesCore.BUILTIN_ROLE_IDS.PUBLIC) {
|
||||
return null
|
||||
}
|
||||
delete user._rev
|
||||
|
@ -55,9 +54,9 @@ function combineMetadataAndUser(user, metadata) {
|
|||
return null
|
||||
}
|
||||
|
||||
exports.syncGlobalUsers = async () => {
|
||||
export async function syncGlobalUsers() {
|
||||
// sync user metadata
|
||||
const db = getAppDB()
|
||||
const db = context.getAppDB()
|
||||
const [users, metadata] = await Promise.all([getGlobalUsers(), rawMetadata()])
|
||||
const toWrite = []
|
||||
for (let user of users) {
|
||||
|
@ -69,13 +68,13 @@ exports.syncGlobalUsers = async () => {
|
|||
await db.bulkDocs(toWrite)
|
||||
}
|
||||
|
||||
exports.syncUser = async function (ctx) {
|
||||
export async function syncUser(ctx: BBContext) {
|
||||
let deleting = false,
|
||||
user
|
||||
user: User | any
|
||||
const userId = ctx.params.id
|
||||
try {
|
||||
user = await getRawGlobalUser(userId)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err && err.status === 404) {
|
||||
user = {}
|
||||
deleting = true
|
||||
|
@ -92,21 +91,21 @@ 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 getProdAppIDs()
|
||||
prodAppIds = await dbCore.getProdAppIDs()
|
||||
} else {
|
||||
prodAppIds = Object.entries(roles)
|
||||
.filter(entry => entry[1] !== BUILTIN_ROLE_IDS.PUBLIC)
|
||||
.filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC)
|
||||
.map(([appId]) => appId)
|
||||
}
|
||||
for (let prodAppId of prodAppIds) {
|
||||
const roleId = roles[prodAppId]
|
||||
const devAppId = getDevelopmentAppID(prodAppId)
|
||||
const devAppId = dbCore.getDevelopmentAppID(prodAppId)
|
||||
for (let appId of [prodAppId, devAppId]) {
|
||||
if (!(await dbExists(appId))) {
|
||||
if (!(await dbCore.dbExists(appId))) {
|
||||
continue
|
||||
}
|
||||
await doInAppContext(appId, async () => {
|
||||
const db = getAppDB()
|
||||
await context.doInAppContext(appId, async () => {
|
||||
const db = context.getAppDB()
|
||||
const metadataId = generateUserMetadataID(userId)
|
||||
let metadata
|
||||
try {
|
||||
|
@ -127,8 +126,8 @@ exports.syncUser = async function (ctx) {
|
|||
? combineMetadataAndUser(user, metadata)
|
||||
: {
|
||||
...metadata,
|
||||
status: UserStatus.INACTIVE,
|
||||
metadata: BUILTIN_ROLE_IDS.PUBLIC,
|
||||
status: constants.UserStatus.INACTIVE,
|
||||
metadata: rolesCore.BUILTIN_ROLE_IDS.PUBLIC,
|
||||
}
|
||||
// if its null then there was no updates required
|
||||
if (combined) {
|
||||
|
@ -142,10 +141,9 @@ exports.syncUser = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.fetchMetadata = async function (ctx) {
|
||||
const database = getAppDB()
|
||||
export async function fetchMetadata(ctx: BBContext) {
|
||||
const global = await getGlobalUsers()
|
||||
const metadata = await rawMetadata(database)
|
||||
const metadata = await rawMetadata()
|
||||
const users = []
|
||||
for (let user of global) {
|
||||
// find the metadata that matches up to the global ID
|
||||
|
@ -162,18 +160,18 @@ exports.fetchMetadata = async function (ctx) {
|
|||
ctx.body = users
|
||||
}
|
||||
|
||||
exports.updateSelfMetadata = async function (ctx) {
|
||||
export async function updateSelfMetadata(ctx: BBContext) {
|
||||
// overwrite the ID with current users
|
||||
ctx.request.body._id = ctx.user._id
|
||||
ctx.request.body._id = ctx.user?._id
|
||||
// make sure no stale rev
|
||||
delete ctx.request.body._rev
|
||||
// make sure no csrf token
|
||||
delete ctx.request.body.csrfToken
|
||||
await exports.updateMetadata(ctx)
|
||||
await updateMetadata(ctx)
|
||||
}
|
||||
|
||||
exports.updateMetadata = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function updateMetadata(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const user = ctx.request.body
|
||||
// this isn't applicable to the user
|
||||
delete user.roles
|
||||
|
@ -184,8 +182,8 @@ exports.updateMetadata = async function (ctx) {
|
|||
ctx.body = await db.put(metadata)
|
||||
}
|
||||
|
||||
exports.destroyMetadata = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
export async function destroyMetadata(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
try {
|
||||
const dbUser = await db.get(ctx.params.id)
|
||||
await db.remove(dbUser._id, dbUser._rev)
|
||||
|
@ -197,18 +195,18 @@ exports.destroyMetadata = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
exports.findMetadata = async function (ctx) {
|
||||
export async function findMetadata(ctx: BBContext) {
|
||||
ctx.body = await getFullUser(ctx, ctx.params.id)
|
||||
}
|
||||
|
||||
exports.setFlag = async function (ctx) {
|
||||
const userId = ctx.user._id
|
||||
export async function setFlag(ctx: BBContext) {
|
||||
const userId = ctx.user?._id
|
||||
const { flag, value } = ctx.request.body
|
||||
if (!flag) {
|
||||
ctx.throw(400, "Must supply a 'flag' field in request body.")
|
||||
}
|
||||
const flagDocId = generateUserFlagID(userId)
|
||||
const db = getAppDB()
|
||||
const flagDocId = generateUserFlagID(userId!)
|
||||
const db = context.getAppDB()
|
||||
let doc
|
||||
try {
|
||||
doc = await db.get(flagDocId)
|
||||
|
@ -220,10 +218,10 @@ exports.setFlag = async function (ctx) {
|
|||
ctx.body = { message: "Flag set successfully" }
|
||||
}
|
||||
|
||||
exports.getFlags = async function (ctx) {
|
||||
const userId = ctx.user._id
|
||||
const docId = generateUserFlagID(userId)
|
||||
const db = getAppDB()
|
||||
export async function getFlags(ctx: BBContext) {
|
||||
const userId = ctx.user?._id
|
||||
const docId = generateUserFlagID(userId!)
|
||||
const db = context.getAppDB()
|
||||
let doc
|
||||
try {
|
||||
doc = await db.get(docId)
|
|
@ -1,4 +1,6 @@
|
|||
exports.csv = function (headers, rows) {
|
||||
import { Row } from "@budibase/types"
|
||||
|
||||
export function csv(headers: string[], rows: Row[]) {
|
||||
let csv = headers.map(key => `"${key}"`).join(",")
|
||||
|
||||
for (let row of rows) {
|
||||
|
@ -16,11 +18,11 @@ exports.csv = function (headers, rows) {
|
|||
return csv
|
||||
}
|
||||
|
||||
exports.json = function (headers, rows) {
|
||||
export function json(headers: string[], rows: Row[]) {
|
||||
return JSON.stringify(rows, undefined, 2)
|
||||
}
|
||||
|
||||
exports.ExportFormats = {
|
||||
export const ExportFormats = {
|
||||
CSV: "csv",
|
||||
JSON: "json",
|
||||
}
|
|
@ -1,21 +1,29 @@
|
|||
const viewTemplate = require("./viewBuilder")
|
||||
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
||||
const exporters = require("./exporters")
|
||||
const { saveView, getView, getViews, deleteView } = require("./utils")
|
||||
const { fetchView } = require("../row")
|
||||
const { FieldTypes } = require("../../../constants")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
const { DocumentType } = require("../../../db/utils")
|
||||
const { cloneDeep, isEqual } = require("lodash")
|
||||
const sdk = require("../../../sdk")
|
||||
import viewTemplate from "./viewBuilder"
|
||||
import { apiFileReturn } from "../../../utilities/fileSystem"
|
||||
import * as exporters from "./exporters"
|
||||
import { deleteView, getView, getViews, saveView } from "./utils"
|
||||
import { fetchView } from "../row"
|
||||
import { FieldTypes } from "../../../constants"
|
||||
import { context, events } from "@budibase/backend-core"
|
||||
import { DocumentType } from "../../../db/utils"
|
||||
import sdk from "../../../sdk"
|
||||
import {
|
||||
BBContext,
|
||||
Row,
|
||||
Table,
|
||||
TableExportFormat,
|
||||
TableSchema,
|
||||
View,
|
||||
} from "@budibase/types"
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
const { cloneDeep, isEqual } = require("lodash")
|
||||
|
||||
export async function fetch(ctx: BBContext) {
|
||||
ctx.body = await getViews()
|
||||
}
|
||||
|
||||
exports.save = async ctx => {
|
||||
const db = getAppDB()
|
||||
export async function save(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const { originalName, ...viewToSave } = ctx.request.body
|
||||
const view = viewTemplate(viewToSave)
|
||||
const viewName = viewToSave.name
|
||||
|
@ -47,7 +55,7 @@ exports.save = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
const calculationEvents = async (existingView, newView) => {
|
||||
export async function calculationEvents(existingView: View, newView: View) {
|
||||
const existingCalculation = existingView && existingView.calculation
|
||||
const newCalculation = newView && newView.calculation
|
||||
|
||||
|
@ -68,7 +76,7 @@ const calculationEvents = async (existingView, newView) => {
|
|||
}
|
||||
}
|
||||
|
||||
const filterEvents = async (existingView, newView) => {
|
||||
export async function filterEvents(existingView: View, newView: View) {
|
||||
const hasExistingFilters = !!(
|
||||
existingView &&
|
||||
existingView.filters &&
|
||||
|
@ -93,7 +101,7 @@ const filterEvents = async (existingView, newView) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleViewEvents = async (existingView, newView) => {
|
||||
async function handleViewEvents(existingView: View, newView: View) {
|
||||
if (!existingView) {
|
||||
await events.view.created(newView)
|
||||
} else {
|
||||
|
@ -103,8 +111,8 @@ const handleViewEvents = async (existingView, newView) => {
|
|||
await filterEvents(existingView, newView)
|
||||
}
|
||||
|
||||
exports.destroy = async ctx => {
|
||||
const db = getAppDB()
|
||||
export async function destroy(ctx: BBContext) {
|
||||
const db = context.getAppDB()
|
||||
const viewName = decodeURI(ctx.params.viewName)
|
||||
const view = await deleteView(viewName)
|
||||
const table = await db.get(view.meta.tableId)
|
||||
|
@ -115,11 +123,11 @@ exports.destroy = async ctx => {
|
|||
ctx.body = view
|
||||
}
|
||||
|
||||
exports.exportView = async ctx => {
|
||||
const viewName = decodeURI(ctx.query.view)
|
||||
export async function exportView(ctx: BBContext) {
|
||||
const viewName = decodeURI(ctx.query.view as string)
|
||||
const view = await getView(viewName)
|
||||
|
||||
const format = ctx.query.format
|
||||
const format = ctx.query.format as string
|
||||
if (!format || !Object.values(exporters.ExportFormats).includes(format)) {
|
||||
ctx.throw(400, "Format must be specified, either csv or json")
|
||||
}
|
||||
|
@ -130,6 +138,7 @@ exports.exportView = async ctx => {
|
|||
ctx.query = {
|
||||
group: view.meta.groupBy,
|
||||
calculation: view.meta.calculation,
|
||||
// @ts-ignore
|
||||
stats: !!view.meta.field,
|
||||
field: view.meta.field,
|
||||
}
|
||||
|
@ -140,11 +149,11 @@ exports.exportView = async ctx => {
|
|||
}
|
||||
|
||||
await fetchView(ctx)
|
||||
let rows = ctx.body
|
||||
let rows = ctx.body as Row[]
|
||||
|
||||
let schema = view && view.meta && view.meta.schema
|
||||
let schema: TableSchema = view && view.meta && view.meta.schema
|
||||
const tableId = ctx.params.tableId || view.meta.tableId
|
||||
const table = await sdk.tables.getTable(tableId)
|
||||
const table: Table = await sdk.tables.getTable(tableId)
|
||||
if (!schema) {
|
||||
schema = table.schema
|
||||
}
|
||||
|
@ -175,15 +184,15 @@ exports.exportView = async ctx => {
|
|||
|
||||
// Export part
|
||||
let headers = Object.keys(schema)
|
||||
const exporter = exporters[format]
|
||||
const exporter = format === "csv" ? exporters.csv : exporters.json
|
||||
const filename = `${viewName}.${format}`
|
||||
// send down the file
|
||||
ctx.attachment(filename)
|
||||
ctx.body = apiFileReturn(exporter(headers, rows))
|
||||
|
||||
if (viewName.startsWith(DocumentType.TABLE)) {
|
||||
await events.table.exported(table, format)
|
||||
await events.table.exported(table, format as TableExportFormat)
|
||||
} else {
|
||||
await events.view.exported(table, format)
|
||||
await events.view.exported(table, format as TableExportFormat)
|
||||
}
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
const {
|
||||
import {
|
||||
ViewName,
|
||||
generateMemoryViewID,
|
||||
getMemoryViewParams,
|
||||
DocumentType,
|
||||
SEPARATOR,
|
||||
} = require("../../../db/utils")
|
||||
const env = require("../../../environment")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const viewBuilder = require("./viewBuilder")
|
||||
} from "../../../db/utils"
|
||||
import env from "../../../environment"
|
||||
import { context } from "@budibase/backend-core"
|
||||
import viewBuilder from "./viewBuilder"
|
||||
import { Database } from "@budibase/types"
|
||||
|
||||
exports.getView = async viewName => {
|
||||
const db = getAppDB()
|
||||
export async function getView(viewName: string) {
|
||||
const db = context.getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
return designDoc.views[viewName]
|
||||
|
@ -23,7 +24,7 @@ exports.getView = async viewName => {
|
|||
try {
|
||||
const viewDoc = await db.get(generateMemoryViewID(viewName))
|
||||
return viewDoc.view
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
// Return null when PouchDB doesn't found the view
|
||||
if (err.status === 404) {
|
||||
return null
|
||||
|
@ -34,14 +35,15 @@ exports.getView = async viewName => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getViews = async () => {
|
||||
const db = getAppDB()
|
||||
export async function getViews() {
|
||||
const db = context.getAppDB()
|
||||
const response = []
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
for (let name of Object.keys(designDoc.views)) {
|
||||
// Only return custom views, not built ins
|
||||
if (Object.values(ViewName).indexOf(name) !== -1) {
|
||||
const viewNames = Object.values(ViewName) as string[]
|
||||
if (viewNames.indexOf(name) !== -1) {
|
||||
continue
|
||||
}
|
||||
response.push({
|
||||
|
@ -67,8 +69,12 @@ exports.getViews = async () => {
|
|||
return response
|
||||
}
|
||||
|
||||
exports.saveView = async (originalName, viewName, viewTemplate) => {
|
||||
const db = getAppDB()
|
||||
export async function saveView(
|
||||
originalName: string | null,
|
||||
viewName: string,
|
||||
viewTemplate: any
|
||||
) {
|
||||
const db = context.getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
designDoc.views = {
|
||||
|
@ -83,7 +89,7 @@ exports.saveView = async (originalName, viewName, viewTemplate) => {
|
|||
} else {
|
||||
const id = generateMemoryViewID(viewName)
|
||||
const originalId = originalName ? generateMemoryViewID(originalName) : null
|
||||
const viewDoc = {
|
||||
const viewDoc: any = {
|
||||
_id: id,
|
||||
view: viewTemplate,
|
||||
name: viewName,
|
||||
|
@ -105,8 +111,8 @@ exports.saveView = async (originalName, viewName, viewTemplate) => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.deleteView = async viewName => {
|
||||
const db = getAppDB()
|
||||
export async function deleteView(viewName: string) {
|
||||
const db = context.getAppDB()
|
||||
if (env.SELF_HOSTED) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = designDoc.views[viewName]
|
||||
|
@ -121,7 +127,7 @@ exports.deleteView = async viewName => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.migrateToInMemoryView = async (db, viewName) => {
|
||||
export async function migrateToInMemoryView(db: Database, viewName: string) {
|
||||
// delete the view initially
|
||||
const designDoc = await db.get("_design/database")
|
||||
// run the view back through the view builder to update it
|
||||
|
@ -131,7 +137,7 @@ exports.migrateToInMemoryView = async (db, viewName) => {
|
|||
await exports.saveView(db, null, viewName, view)
|
||||
}
|
||||
|
||||
exports.migrateToDesignView = async (db, viewName) => {
|
||||
export async function migrateToDesignView(db: Database, viewName: string) {
|
||||
let view = await db.get(generateMemoryViewID(viewName))
|
||||
const designDoc = await db.get("_design/database")
|
||||
designDoc.views[viewName] = viewBuilder(view.view.meta)
|
||||
|
@ -139,7 +145,7 @@ exports.migrateToDesignView = async (db, viewName) => {
|
|||
await db.remove(view._id, view._rev)
|
||||
}
|
||||
|
||||
exports.getFromDesignDoc = async (db, viewName) => {
|
||||
export async function getFromDesignDoc(db: Database, viewName: string) {
|
||||
const designDoc = await db.get("_design/database")
|
||||
let view = designDoc.views[viewName]
|
||||
if (view == null) {
|
||||
|
@ -148,7 +154,7 @@ exports.getFromDesignDoc = async (db, viewName) => {
|
|||
return view
|
||||
}
|
||||
|
||||
exports.getFromMemoryDoc = async (db, viewName) => {
|
||||
export async function getFromMemoryDoc(db: Database, viewName: string) {
|
||||
let view = await db.get(generateMemoryViewID(viewName))
|
||||
if (view) {
|
||||
view = view.view
|
|
@ -1,20 +1,15 @@
|
|||
const Router = require("@koa/router")
|
||||
const {
|
||||
buildAuthMiddleware,
|
||||
auditLog,
|
||||
buildTenancyMiddleware,
|
||||
} = require("@budibase/backend-core/auth")
|
||||
const { errors } = require("@budibase/backend-core")
|
||||
const currentApp = require("../middleware/currentapp")
|
||||
import Router from "@koa/router"
|
||||
import { errors, auth } from "@budibase/backend-core"
|
||||
import currentApp from "../middleware/currentapp"
|
||||
import zlib from "zlib"
|
||||
import { mainRoutes, staticRoutes, publicRoutes } from "./routes"
|
||||
import pkg from "../../package.json"
|
||||
import env from "../environment"
|
||||
import { middleware as pro } from "@budibase/pro"
|
||||
export { shutdown } from "./routes/public"
|
||||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
const { mainRoutes, staticRoutes, publicRoutes } = require("./routes")
|
||||
const pkg = require("../../package.json")
|
||||
const env = require("../environment")
|
||||
const { middleware: pro } = require("@budibase/pro")
|
||||
const { shutdown } = require("./routes/public")
|
||||
|
||||
const router = new Router()
|
||||
export const router: Router = new Router()
|
||||
|
||||
router.get("/health", ctx => (ctx.status = 200))
|
||||
router.get("/version", ctx => (ctx.body = pkg.version))
|
||||
|
@ -42,7 +37,7 @@ router
|
|||
// re-direct before any middlewares occur
|
||||
.redirect("/", "/builder")
|
||||
.use(
|
||||
buildAuthMiddleware(null, {
|
||||
auth.buildAuthMiddleware(null, {
|
||||
publicAllowed: true,
|
||||
})
|
||||
)
|
||||
|
@ -50,19 +45,20 @@ router
|
|||
// the server can be public anywhere, so nowhere should throw errors
|
||||
// if the tenancy has not been set, it'll have to be discovered at application layer
|
||||
.use(
|
||||
buildTenancyMiddleware(null, null, {
|
||||
auth.buildTenancyMiddleware(null, null, {
|
||||
noTenancyRequired: true,
|
||||
})
|
||||
)
|
||||
.use(pro.licensing())
|
||||
// @ts-ignore
|
||||
.use(currentApp)
|
||||
.use(auditLog)
|
||||
.use(auth.auditLog)
|
||||
|
||||
// error handling middleware
|
||||
router.use(async (ctx, next) => {
|
||||
try {
|
||||
await next()
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
ctx.status = err.status || err.statusCode || 500
|
||||
const error = errors.getPublicError(err)
|
||||
ctx.body = {
|
||||
|
@ -91,6 +87,3 @@ router.use(publicRoutes.allowedMethods())
|
|||
// WARNING - static routes will catch everything else after them this must be last
|
||||
router.use(staticRoutes.routes())
|
||||
router.use(staticRoutes.allowedMethods())
|
||||
|
||||
module.exports.router = router
|
||||
module.exports.shutdown = shutdown
|
|
@ -1,9 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/analytics")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router.get("/api/bbtel", controller.isEnabled)
|
||||
router.post("/api/bbtel/ping", controller.ping)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,9 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/analytics"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get("/api/bbtel", controller.isEnabled)
|
||||
router.post("/api/bbtel/ping", controller.ping)
|
||||
|
||||
export = router
|
|
@ -1,12 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/apikeys")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/keys", authorized(BUILDER), controller.fetch)
|
||||
.put("/api/keys/:key", authorized(BUILDER), controller.update)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,12 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/apikeys"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/keys", authorized(permissions.BUILDER), controller.fetch)
|
||||
.put("/api/keys/:key", authorized(permissions.BUILDER), controller.update)
|
||||
|
||||
export = router
|
|
@ -1,16 +1,20 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/application"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { BUILDER } from "@budibase/backend-core/permissions"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import { applicationValidator } from "./utils/validators"
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.post("/api/applications/:appId/sync", authorized(BUILDER), controller.sync)
|
||||
.post(
|
||||
"/api/applications/:appId/sync",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.sync
|
||||
)
|
||||
.post(
|
||||
"/api/applications",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
applicationValidator(),
|
||||
controller.create
|
||||
)
|
||||
|
@ -19,20 +23,24 @@ router
|
|||
.get("/api/applications/:appId/appPackage", controller.fetchAppPackage)
|
||||
.put(
|
||||
"/api/applications/:appId",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
applicationValidator({ isCreate: false }),
|
||||
controller.update
|
||||
)
|
||||
.post(
|
||||
"/api/applications/:appId/client/update",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
controller.updateClient
|
||||
)
|
||||
.post(
|
||||
"/api/applications/:appId/client/revert",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
controller.revertClient
|
||||
)
|
||||
.delete("/api/applications/:appId", authorized(BUILDER), controller.destroy)
|
||||
.delete(
|
||||
"/api/applications/:appId",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
|
||||
export default router
|
||||
export = router
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/auth"
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get("/api/self", controller.fetchSelf)
|
||||
|
||||
export default router
|
||||
export = router
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/automation")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const {
|
||||
BUILDER,
|
||||
PermissionLevel,
|
||||
PermissionType,
|
||||
} = require("@budibase/backend-core/permissions")
|
||||
const { bodyResource, paramResource } = require("../../middleware/resourceId")
|
||||
const {
|
||||
middleware: appInfoMiddleware,
|
||||
AppType,
|
||||
} = require("../../middleware/appInfo")
|
||||
const { automationValidator } = require("./utils/validators")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/automations/trigger/list",
|
||||
authorized(BUILDER),
|
||||
controller.getTriggerList
|
||||
)
|
||||
.get(
|
||||
"/api/automations/action/list",
|
||||
authorized(BUILDER),
|
||||
controller.getActionList
|
||||
)
|
||||
.get(
|
||||
"/api/automations/definitions/list",
|
||||
authorized(BUILDER),
|
||||
controller.getDefinitionList
|
||||
)
|
||||
.get("/api/automations", authorized(BUILDER), controller.fetch)
|
||||
.get(
|
||||
"/api/automations/:id",
|
||||
paramResource("id"),
|
||||
authorized(BUILDER),
|
||||
controller.find
|
||||
)
|
||||
.put(
|
||||
"/api/automations",
|
||||
bodyResource("_id"),
|
||||
authorized(BUILDER),
|
||||
automationValidator(true),
|
||||
controller.update
|
||||
)
|
||||
.post(
|
||||
"/api/automations",
|
||||
authorized(BUILDER),
|
||||
automationValidator(false),
|
||||
controller.create
|
||||
)
|
||||
.post(
|
||||
"/api/automations/logs/search",
|
||||
authorized(BUILDER),
|
||||
controller.logSearch
|
||||
)
|
||||
.delete(
|
||||
"/api/automations/logs",
|
||||
authorized(BUILDER),
|
||||
controller.clearLogError
|
||||
)
|
||||
.delete(
|
||||
"/api/automations/:id/:rev",
|
||||
paramResource("id"),
|
||||
authorized(BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
.post(
|
||||
"/api/automations/:id/trigger",
|
||||
appInfoMiddleware({ appType: AppType.PROD }),
|
||||
paramResource("id"),
|
||||
authorized(PermissionType.AUTOMATION, PermissionLevel.EXECUTE),
|
||||
controller.trigger
|
||||
)
|
||||
.post(
|
||||
"/api/automations/:id/test",
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
paramResource("id"),
|
||||
authorized(PermissionType.AUTOMATION, PermissionLevel.EXECUTE),
|
||||
controller.test
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,87 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/automation"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import { bodyResource, paramResource } from "../../middleware/resourceId"
|
||||
import {
|
||||
middleware as appInfoMiddleware,
|
||||
AppType,
|
||||
} from "../../middleware/appInfo"
|
||||
import { automationValidator } from "./utils/validators"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/automations/trigger/list",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.getTriggerList
|
||||
)
|
||||
.get(
|
||||
"/api/automations/action/list",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.getActionList
|
||||
)
|
||||
.get(
|
||||
"/api/automations/definitions/list",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.getDefinitionList
|
||||
)
|
||||
.get("/api/automations", authorized(permissions.BUILDER), controller.fetch)
|
||||
.get(
|
||||
"/api/automations/:id",
|
||||
paramResource("id"),
|
||||
authorized(permissions.BUILDER),
|
||||
controller.find
|
||||
)
|
||||
.put(
|
||||
"/api/automations",
|
||||
bodyResource("_id"),
|
||||
authorized(permissions.BUILDER),
|
||||
automationValidator(true),
|
||||
controller.update
|
||||
)
|
||||
.post(
|
||||
"/api/automations",
|
||||
authorized(permissions.BUILDER),
|
||||
automationValidator(false),
|
||||
controller.create
|
||||
)
|
||||
.post(
|
||||
"/api/automations/logs/search",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.logSearch
|
||||
)
|
||||
.delete(
|
||||
"/api/automations/logs",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.clearLogError
|
||||
)
|
||||
.delete(
|
||||
"/api/automations/:id/:rev",
|
||||
paramResource("id"),
|
||||
authorized(permissions.BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
.post(
|
||||
"/api/automations/:id/trigger",
|
||||
appInfoMiddleware({ appType: AppType.PROD }),
|
||||
paramResource("id"),
|
||||
authorized(
|
||||
permissions.PermissionType.AUTOMATION,
|
||||
permissions.PermissionLevel.EXECUTE
|
||||
),
|
||||
controller.trigger
|
||||
)
|
||||
.post(
|
||||
"/api/automations/:id/test",
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
paramResource("id"),
|
||||
authorized(
|
||||
permissions.PermissionType.AUTOMATION,
|
||||
permissions.PermissionLevel.EXECUTE
|
||||
),
|
||||
controller.test
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,10 +1,14 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/backup"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { BUILDER } from "@budibase/backend-core/permissions"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get("/api/backups/export", authorized(BUILDER), controller.exportAppDump)
|
||||
router.get(
|
||||
"/api/backups/export",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.exportAppDump
|
||||
)
|
||||
|
||||
export default router
|
||||
export = router
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/cloud")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/cloud/export", authorized(BUILDER), controller.exportApps)
|
||||
// has to be public, only run if apps don't exist
|
||||
.post("/api/cloud/import", controller.importApps)
|
||||
.get("/api/cloud/import/complete", controller.hasBeenImported)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,18 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/cloud"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/cloud/export",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.exportApps
|
||||
)
|
||||
// has to be public, only run if apps don't exist
|
||||
.post("/api/cloud/import", controller.importApps)
|
||||
.get("/api/cloud/import/complete", controller.hasBeenImported)
|
||||
|
||||
export = router
|
|
@ -1,14 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/component")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router.get(
|
||||
"/api/:appId/components/definitions",
|
||||
authorized(BUILDER),
|
||||
controller.fetchAppComponentDefinitions
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,14 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/component"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router.get(
|
||||
"/api/:appId/components/definitions",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.fetchAppComponentDefinitions
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,51 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const datasourceController = require("../controllers/datasource")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const {
|
||||
BUILDER,
|
||||
PermissionLevel,
|
||||
PermissionType,
|
||||
} = require("@budibase/backend-core/permissions")
|
||||
const {
|
||||
datasourceValidator,
|
||||
datasourceQueryValidator,
|
||||
} = require("./utils/validators")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/datasources", authorized(BUILDER), datasourceController.fetch)
|
||||
.get(
|
||||
"/api/datasources/:datasourceId",
|
||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||
datasourceController.find
|
||||
)
|
||||
.put(
|
||||
"/api/datasources/:datasourceId",
|
||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||
datasourceController.update
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/query",
|
||||
authorized(PermissionType.TABLE, PermissionLevel.READ),
|
||||
datasourceQueryValidator(),
|
||||
datasourceController.query
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/schema",
|
||||
authorized(BUILDER),
|
||||
datasourceController.buildSchemaFromDb
|
||||
)
|
||||
.post(
|
||||
"/api/datasources",
|
||||
authorized(BUILDER),
|
||||
datasourceValidator(),
|
||||
datasourceController.save
|
||||
)
|
||||
.delete(
|
||||
"/api/datasources/:datasourceId/:revId",
|
||||
authorized(BUILDER),
|
||||
datasourceController.destroy
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,60 @@
|
|||
import Router from "@koa/router"
|
||||
import * as datasourceController from "../controllers/datasource"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import {
|
||||
datasourceValidator,
|
||||
datasourceQueryValidator,
|
||||
} from "./utils/validators"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/datasources",
|
||||
authorized(permissions.BUILDER),
|
||||
datasourceController.fetch
|
||||
)
|
||||
.get(
|
||||
"/api/datasources/:datasourceId",
|
||||
authorized(
|
||||
permissions.PermissionType.TABLE,
|
||||
permissions.PermissionLevel.READ
|
||||
),
|
||||
datasourceController.find
|
||||
)
|
||||
.put(
|
||||
"/api/datasources/:datasourceId",
|
||||
authorized(
|
||||
permissions.PermissionType.TABLE,
|
||||
permissions.PermissionLevel.READ
|
||||
),
|
||||
datasourceController.update
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/query",
|
||||
authorized(
|
||||
permissions.PermissionType.TABLE,
|
||||
permissions.PermissionLevel.READ
|
||||
),
|
||||
datasourceQueryValidator(),
|
||||
datasourceController.query
|
||||
)
|
||||
.post(
|
||||
"/api/datasources/:datasourceId/schema",
|
||||
authorized(permissions.BUILDER),
|
||||
datasourceController.buildSchemaFromDb
|
||||
)
|
||||
.post(
|
||||
"/api/datasources",
|
||||
authorized(permissions.BUILDER),
|
||||
datasourceValidator(),
|
||||
datasourceController.save
|
||||
)
|
||||
.delete(
|
||||
"/api/datasources/:datasourceId/:revId",
|
||||
authorized(permissions.BUILDER),
|
||||
datasourceController.destroy
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,17 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/deploy")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/deployments", authorized(BUILDER), controller.fetchDeployments)
|
||||
.get(
|
||||
"/api/deploy/:deploymentId",
|
||||
authorized(BUILDER),
|
||||
controller.deploymentProgress
|
||||
)
|
||||
.post("/api/deploy", authorized(BUILDER), controller.deployApp)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,21 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/deploy"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/deployments",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.fetchDeployments
|
||||
)
|
||||
.get(
|
||||
"/api/deploy/:deploymentId",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.deploymentProgress
|
||||
)
|
||||
.post("/api/deploy", authorized(permissions.BUILDER), controller.deployApp)
|
||||
|
||||
export = router
|
|
@ -1,26 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/dev")
|
||||
const env = require("../../environment")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
function redirectPath(path) {
|
||||
router
|
||||
.get(`/api/${path}/:devPath(.*)`, controller.buildRedirectGet(path))
|
||||
.post(`/api/${path}/:devPath(.*)`, controller.buildRedirectPost(path))
|
||||
.delete(`/api/${path}/:devPath(.*)`, controller.buildRedirectDelete(path))
|
||||
}
|
||||
|
||||
if (env.isDev() || env.isTest()) {
|
||||
redirectPath("global")
|
||||
redirectPath("system")
|
||||
}
|
||||
|
||||
router
|
||||
.get("/api/dev/version", authorized(BUILDER), controller.getBudibaseVersion)
|
||||
.delete("/api/dev/:appId/lock", authorized(BUILDER), controller.clearLock)
|
||||
.post("/api/dev/:appId/revert", authorized(BUILDER), controller.revert)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,38 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/dev"
|
||||
import env from "../../environment"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
function redirectPath(path: string) {
|
||||
router
|
||||
.get(`/api/${path}/:devPath(.*)`, controller.buildRedirectGet(path))
|
||||
.post(`/api/${path}/:devPath(.*)`, controller.buildRedirectPost(path))
|
||||
.delete(`/api/${path}/:devPath(.*)`, controller.buildRedirectDelete(path))
|
||||
}
|
||||
|
||||
if (env.isDev() || env.isTest()) {
|
||||
redirectPath("global")
|
||||
redirectPath("system")
|
||||
}
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/dev/version",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.getBudibaseVersion
|
||||
)
|
||||
.delete(
|
||||
"/api/dev/:appId/lock",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.clearLock
|
||||
)
|
||||
.post(
|
||||
"/api/dev/:appId/revert",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.revert
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,12 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/integration")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/integrations", authorized(BUILDER), controller.fetch)
|
||||
.get("/api/integrations/:type", authorized(BUILDER), controller.find)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,16 @@
|
|||
import Router from "@koa/router"
|
||||
import controller from "../controllers/integration"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/integrations", authorized(permissions.BUILDER), controller.fetch)
|
||||
.get(
|
||||
"/api/integrations/:type",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.find
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,16 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
const controller = require("../controllers/layout")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.post("/api/layouts", authorized(BUILDER), controller.save)
|
||||
.delete(
|
||||
"/api/layouts/:layoutId/:layoutRev",
|
||||
authorized(BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,16 @@
|
|||
import Router from "@koa/router"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import * as controller from "../controllers/layout"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.post("/api/layouts", authorized(permissions.BUILDER), controller.save)
|
||||
.delete(
|
||||
"/api/layouts/:layoutId/:layoutRev",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,38 +1,38 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/metadata")
|
||||
const {
|
||||
middleware: appInfoMiddleware,
|
||||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/metadata"
|
||||
import {
|
||||
middleware as appInfoMiddleware,
|
||||
AppType,
|
||||
} = require("../../middleware/appInfo")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
} from "../../middleware/appInfo"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.post(
|
||||
"/api/metadata/:type/:entityId",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
controller.saveMetadata
|
||||
)
|
||||
.delete(
|
||||
"/api/metadata/:type/:entityId",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
controller.deleteMetadata
|
||||
)
|
||||
.get(
|
||||
"/api/metadata/type",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
controller.getTypes
|
||||
)
|
||||
.get(
|
||||
"/api/metadata/:type/:entityId",
|
||||
authorized(BUILDER),
|
||||
authorized(permissions.BUILDER),
|
||||
appInfoMiddleware({ appType: AppType.DEV }),
|
||||
controller.getMetadata
|
||||
)
|
||||
|
||||
module.exports = router
|
||||
export = router
|
|
@ -1,14 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const migrationsController = require("../controllers/migrations")
|
||||
const router = new Router()
|
||||
const { internalApi } = require("@budibase/backend-core/auth")
|
||||
|
||||
router
|
||||
.post("/api/migrations/run", internalApi, migrationsController.migrate)
|
||||
.get(
|
||||
"/api/migrations/definitions",
|
||||
internalApi,
|
||||
migrationsController.fetchDefinitions
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,14 @@
|
|||
import Router from "@koa/router"
|
||||
import * as migrationsController from "../controllers/migrations"
|
||||
import { auth } from "@budibase/backend-core"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.post("/api/migrations/run", auth.internalApi, migrationsController.migrate)
|
||||
.get(
|
||||
"/api/migrations/definitions",
|
||||
auth.internalApi,
|
||||
migrationsController.fetchDefinitions
|
||||
)
|
||||
export = router
|
|
@ -1,33 +0,0 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/permission")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const { BUILDER } = require("@budibase/backend-core/permissions")
|
||||
const { permissionValidator } = require("./utils/validators")
|
||||
|
||||
const router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/permission/builtin", authorized(BUILDER), controller.fetchBuiltin)
|
||||
.get("/api/permission/levels", authorized(BUILDER), controller.fetchLevels)
|
||||
.get("/api/permission", authorized(BUILDER), controller.fetch)
|
||||
.get(
|
||||
"/api/permission/:resourceId",
|
||||
authorized(BUILDER),
|
||||
controller.getResourcePerms
|
||||
)
|
||||
// adding a specific role/level for the resource overrides the underlying access control
|
||||
.post(
|
||||
"/api/permission/:roleId/:resourceId/:level",
|
||||
authorized(BUILDER),
|
||||
permissionValidator(),
|
||||
controller.addPermission
|
||||
)
|
||||
// deleting the level defaults it back the underlying access control for the resource
|
||||
.delete(
|
||||
"/api/permission/:roleId/:resourceId/:level",
|
||||
authorized(BUILDER),
|
||||
permissionValidator(),
|
||||
controller.removePermission
|
||||
)
|
||||
|
||||
module.exports = router
|
|
@ -0,0 +1,41 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/permission"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import { permissionValidator } from "./utils/validators"
|
||||
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get(
|
||||
"/api/permission/builtin",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.fetchBuiltin
|
||||
)
|
||||
.get(
|
||||
"/api/permission/levels",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.fetchLevels
|
||||
)
|
||||
.get("/api/permission", authorized(permissions.BUILDER), controller.fetch)
|
||||
.get(
|
||||
"/api/permission/:resourceId",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.getResourcePerms
|
||||
)
|
||||
// adding a specific role/level for the resource overrides the underlying access control
|
||||
.post(
|
||||
"/api/permission/:roleId/:resourceId/:level",
|
||||
authorized(permissions.BUILDER),
|
||||
permissionValidator(),
|
||||
controller.addPermission
|
||||
)
|
||||
// deleting the level defaults it back the underlying access control for the resource
|
||||
.delete(
|
||||
"/api/permission/:roleId/:resourceId/:level",
|
||||
authorized(permissions.BUILDER),
|
||||
permissionValidator(),
|
||||
controller.removePermission
|
||||
)
|
||||
|
||||
export = router
|
|
@ -1,14 +1,22 @@
|
|||
import Router from "@koa/router"
|
||||
import * as controller from "../controllers/plugin"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { BUILDER } from "@budibase/backend-core/permissions"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.post("/api/plugin/upload", authorized(BUILDER), controller.upload)
|
||||
.post("/api/plugin", authorized(BUILDER), controller.create)
|
||||
.get("/api/plugin", authorized(BUILDER), controller.fetch)
|
||||
.delete("/api/plugin/:pluginId", authorized(BUILDER), controller.destroy)
|
||||
.post(
|
||||
"/api/plugin/upload",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.upload
|
||||
)
|
||||
.post("/api/plugin", authorized(permissions.BUILDER), controller.create)
|
||||
.get("/api/plugin", authorized(permissions.BUILDER), controller.fetch)
|
||||
.delete(
|
||||
"/api/plugin/:pluginId",
|
||||
authorized(permissions.BUILDER),
|
||||
controller.destroy
|
||||
)
|
||||
|
||||
export default router
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
const Router = require("@koa/router")
|
||||
const queryController = require("../controllers/query")
|
||||
const authorized = require("../../middleware/authorized")
|
||||
const {
|
||||
PermissionLevel,
|
||||
PermissionType,
|
||||
BUILDER,
|
||||
} = require("@budibase/backend-core/permissions")
|
||||
const {
|
||||
import Router from "@koa/router"
|
||||
import * as queryController from "../controllers/query"
|
||||
import authorized from "../../middleware/authorized"
|
||||
import { permissions } from "@budibase/backend-core"
|
||||
import {
|
||||
bodyResource,
|
||||
bodySubResource,
|
||||
paramResource,
|
||||
} = require("../../middleware/resourceId")
|
||||
const {
|
||||
} from "../../middleware/resourceId"
|
||||
import {
|
||||
generateQueryPreviewValidation,
|
||||
generateQueryValidation,
|
||||
} = require("../controllers/query/validation")
|
||||
} from "../controllers/query/validation"
|
||||
const { BUILDER, PermissionType, PermissionLevel } = permissions
|
||||
|
||||
const router = new Router()
|
||||
const router: Router = new Router()
|
||||
|
||||
router
|
||||
.get("/api/queries", authorized(BUILDER), queryController.fetch)
|
||||
|
@ -48,17 +45,17 @@ router
|
|||
authorized(PermissionType.QUERY, PermissionLevel.WRITE),
|
||||
queryController.executeV1
|
||||
)
|
||||
.post(
|
||||
"/api/v2/queries/:queryId",
|
||||
paramResource("queryId"),
|
||||
authorized(PermissionType.QUERY, PermissionLevel.WRITE),
|
||||
queryController.executeV2
|
||||
)
|
||||
.delete(
|
||||
"/api/queries/:queryId/:revId",
|
||||
paramResource("queryId"),
|
||||
authorized(BUILDER),
|
||||
queryController.destroy
|
||||
)
|
||||
.post(
|
||||
"/api/v2/queries/:queryId",
|
||||
paramResource("queryId"),
|
||||
authorized(PermissionType.QUERY, PermissionLevel.WRITE),
|
||||
queryController.executeV2 as any
|
||||
)
|
||||
|
||||
module.exports = router
|
||||
export = router
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue