diff --git a/packages/builder/src/builderStore/api.js b/packages/builder/src/builderStore/api.js index ae81df10f6..2e683238bc 100644 --- a/packages/builder/src/builderStore/api.js +++ b/packages/builder/src/builderStore/api.js @@ -2,21 +2,23 @@ import { store } from "./index" import { get as svelteGet } from "svelte/store" import { removeCookie, Cookies } from "./cookies" -const apiCall = - method => - async (url, body, headers = { "Content-Type": "application/json" }) => { - headers["x-budibase-app-id"] = svelteGet(store).appId - const json = headers["Content-Type"] === "application/json" - const resp = await fetch(url, { - method: method, - body: json ? JSON.stringify(body) : body, - headers, - }) - if (resp.status === 403) { - removeCookie(Cookies.Auth) - } - return resp +const apiCall = method => async ( + url, + body, + headers = { "Content-Type": "application/json" } +) => { + headers["x-budibase-app-id"] = svelteGet(store).appId + const json = headers["Content-Type"] === "application/json" + const resp = await fetch(url, { + method: method, + body: json ? JSON.stringify(body) : body, + headers, + }) + if (resp.status === 403) { + removeCookie(Cookies.Auth) } + return resp +} export const post = apiCall("POST") export const get = apiCall("GET") diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index c372f27bb7..7a01bccfab 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -100,10 +100,9 @@ const automationActions = store => ({ }, deleteAutomationBlock: block => { store.update(state => { - const idx = - state.selectedAutomation.automation.definition.steps.findIndex( - x => x.id === block.id - ) + const idx = state.selectedAutomation.automation.definition.steps.findIndex( + x => x.id === block.id + ) state.selectedAutomation.deleteBlock(block.id) // Select next closest step diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/Budibase.svelte b/packages/builder/src/components/backend/DatasourceNavigator/icons/Budibase.svelte index e335dfe9f2..02ecf89027 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/icons/Budibase.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/Budibase.svelte @@ -2,81 +2,125 @@ export let width = "100" export let height = "100" - - - - - - - + + + + + + - - - + + + - - - - - - + + + + + + - - - + + + - - - - - - + + + + + + - - - - - + c0.44,0,0.86-0.09,1.24-0.26c0.39-0.17,0.72-0.41,1.01-0.71c0.29-0.3,0.52-0.65,0.69-1.05C19.21,29.16,19.3,28.75,19.3,28.31z" + /> + + diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 01e0c5918b..37e7f520f3 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -59,7 +59,9 @@ Columns - {#each context.filter( context => context.readableBinding.match(searchRgx) ) as { readableBinding }} + {#each context.filter(context => + context.readableBinding.match(searchRgx) + ) as { readableBinding }} { value = addToText(value, getCaretPosition(), readableBinding) @@ -75,7 +77,9 @@ Components - {#each instance.filter( instance => instance.readableBinding.match(searchRgx) ) as { readableBinding }} + {#each instance.filter(instance => + instance.readableBinding.match(searchRgx) + ) as { readableBinding }} addToText(readableBinding)}> {readableBinding} diff --git a/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte b/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte index 2c0e33227b..dc921dfb27 100644 --- a/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/ServerBindingPanel.svelte @@ -49,7 +49,9 @@ {#each categories as [categoryName, bindings]} {categoryName} - {#each bindings.filter( binding => binding.label.match(searchRgx) ) as binding} + {#each bindings.filter(binding => + binding.label.match(searchRgx) + ) as binding} { diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte index 43f9837232..57c64ca0ed 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/DataSourceSelect.svelte @@ -103,9 +103,8 @@ } function fetchQueryDefinition(query) { - const source = $datasources.list.find( - ds => ds._id === query.datasourceId - ).source + const source = $datasources.list.find(ds => ds._id === query.datasourceId) + .source return $integrations[source].query[query.queryVerb] } diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte index 44f349a324..8c10b47a4d 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/EventsEditor/actions/ExecuteQuery.svelte @@ -18,9 +18,8 @@ ) function fetchQueryDefinition(query) { - const source = $datasources.list.find( - ds => ds._id === query.datasourceId - ).source + const source = $datasources.list.find(ds => ds._id === query.datasourceId) + .source return $integrations[source].query[query.queryVerb] } diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte index 166c305d23..66e610956f 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte @@ -81,22 +81,24 @@ on:change={setUnsaved} /> - - - Queries - $goto("./new")}>Add Query - - - {#each $queries.list.filter(query => query.datasourceId === datasource._id) as query} - onClickQuery(query)}> - {query.name} - {capitalise(query.queryVerb)} - → - - {/each} - + + + Queries + $goto("./new")}>Add Query + + + {#each $queries.list.filter(query => query.datasourceId === datasource._id) as query} + onClickQuery(query)}> + {query.name} + {capitalise(query.queryVerb)} + → + + {/each} + {#if datasource.plus} - Fetch Tables From Database + Fetch Tables From Database {/if} diff --git a/packages/builder/src/stores/backend/datasources.js b/packages/builder/src/stores/backend/datasources.js index df669f4fd8..7a90d01807 100644 --- a/packages/builder/src/stores/backend/datasources.js +++ b/packages/builder/src/stores/backend/datasources.js @@ -28,7 +28,7 @@ export function createDatasourcesStore() { update(state => ({ ...state, selected: datasourceId })) queries.update(state => ({ ...state, selected: null })) }, - updateSchema: async (datasource) => { + updateSchema: async datasource => { let url = `/api/datasources/${datasource._id}/schema` const response = await api.post(url) @@ -53,7 +53,7 @@ export function createDatasourcesStore() { }) return json }, - save: async (datasource) => { + save: async datasource => { let url = "/api/datasources" const response = await api.post(url, datasource) diff --git a/packages/builder/src/stores/backend/tests/fixtures/queries.js b/packages/builder/src/stores/backend/tests/fixtures/queries.js index f5e595249a..7815d61ea5 100644 --- a/packages/builder/src/stores/backend/tests/fixtures/queries.js +++ b/packages/builder/src/stores/backend/tests/fixtures/queries.js @@ -9,7 +9,8 @@ export const SOME_QUERY = { queryVerb: "read", schema: {}, name: "Speakers", - _id: "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f", + _id: + "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f", _rev: "2-941f8699eb0adf995f8bd59c99203b26", readable: true, } @@ -74,7 +75,8 @@ export const SAVE_QUERY_RESPONSE = { }, }, name: "Speakers", - _id: "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f", + _id: + "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f", _rev: "3-5a64adef494b1e9c793dc91b51ce73c6", readable: true, } diff --git a/packages/server/src/api/controllers/query.js b/packages/server/src/api/controllers/query.js index 737c8c9b01..d584b73e20 100644 --- a/packages/server/src/api/controllers/query.js +++ b/packages/server/src/api/controllers/query.js @@ -160,6 +160,8 @@ exports.execute = async function (ctx) { ) const integration = new Integration(datasource.config) + console.log(query) + // ctx.body = {} // call the relevant CRUD method on the integration class ctx.body = formatResponse(await integration[query.queryVerb](enrichedQuery)) // cleanup diff --git a/packages/server/src/api/controllers/row/external.js b/packages/server/src/api/controllers/row/external.js index 3dd638d326..940bb7bb00 100644 --- a/packages/server/src/api/controllers/row/external.js +++ b/packages/server/src/api/controllers/row/external.js @@ -86,8 +86,11 @@ async function handleRequest( // clean up row on ingress using schema filters = buildFilters(id, filters, table) row = inputProcessing(row, table) - if (operation === DataSourceOperation.DELETE && Object.keys(filters).length === 0) { - throw "Deletion must be filtered in someway" + if ( + operation === DataSourceOperation.DELETE && + Object.keys(filters).length === 0 + ) { + throw "Deletion must be filtered" } let json = { endpoint: { diff --git a/packages/server/src/api/controllers/row/utils.js b/packages/server/src/api/controllers/row/utils.js index 06c2e3faf8..16c48181d1 100644 --- a/packages/server/src/api/controllers/row/utils.js +++ b/packages/server/src/api/controllers/row/utils.js @@ -18,8 +18,8 @@ validateJs.extend(validateJs.validators.datetime, { exports.makeExternalQuery = async (appId, json) => { const datasourceId = json.endpoint.datasourceId - const database = new CouchDB(appId) - const datasource = await database.get(datasourceId) + const db = new CouchDB(appId) + const datasource = await db.get(datasourceId) const Integration = integrations[datasource.source] // query is the opinionated function if (Integration.prototype.query) { diff --git a/packages/server/src/api/controllers/table/index.js b/packages/server/src/api/controllers/table/index.js index e090fba629..2a44eefb15 100644 --- a/packages/server/src/api/controllers/table/index.js +++ b/packages/server/src/api/controllers/table/index.js @@ -9,13 +9,10 @@ const { BudibaseInternalDB, } = require("../../../db/utils") const { FieldTypes } = require("../../../constants") -const { - TableSaveFunctions, - getExternalTable -} = require("./utils") +const { TableSaveFunctions, getExternalTable } = require("./utils") const { isExternalTable, - breakExternalTableId + breakExternalTableId, } = require("../../../integrations/utils") exports.fetch = async function (ctx) { diff --git a/packages/server/src/integrations/elasticsearch.js b/packages/server/src/integrations/elasticsearch.js index 3a52a0278b..be1b945893 100644 --- a/packages/server/src/integrations/elasticsearch.js +++ b/packages/server/src/integrations/elasticsearch.js @@ -2,7 +2,8 @@ const { Client } = require("@elastic/elasticsearch") const { QUERY_TYPES, FIELD_TYPES } = require("./Integration") const SCHEMA = { - docs: "https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html", + docs: + "https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/index.html", description: "Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents.", friendlyName: "ElasticSearch", diff --git a/packages/server/src/integrations/plus/postgres.js b/packages/server/src/integrations/plus/postgres.js index c7edc56f9f..87fd4c2cd2 100644 --- a/packages/server/src/integrations/plus/postgres.js +++ b/packages/server/src/integrations/plus/postgres.js @@ -62,11 +62,11 @@ // "select * from information_schema.columns where table_schema = 'public'" // PRIMARY_KEYS_SQL = ` -// select tc.table_schema, tc.table_name, kc.column_name as primary_key +// select tc.table_schema, tc.table_name, kc.column_name as primary_key // from information_schema.table_constraints tc -// join -// information_schema.key_column_usage kc on kc.table_name = tc.table_name -// and kc.table_schema = tc.table_schema +// join +// information_schema.key_column_usage kc on kc.table_name = tc.table_name +// and kc.table_schema = tc.table_schema // and kc.constraint_name = tc.constraint_name // where tc.constraint_type = 'PRIMARY KEY'; // ` diff --git a/packages/server/src/integrations/postgres.js b/packages/server/src/integrations/postgres.js index d40529defd..2458afa333 100644 --- a/packages/server/src/integrations/postgres.js +++ b/packages/server/src/integrations/postgres.js @@ -153,17 +153,17 @@ class PostgresIntegration extends Sql { this.tables = tables } - async create({ sql }) { + async create(sql) { const response = await internalQuery(this.client, sql) return response.rows.length ? response.rows : [{ created: true }] } - async read({ sql }) { + async read(sql) { const response = await internalQuery(this.client, sql) return response.rows } - async update({ sql }) { + async update(sql) { const response = await internalQuery(this.client, sql) return response.rows.length ? response.rows : [{ updated: true }] } diff --git a/packages/server/src/integrations/utils.js b/packages/server/src/integrations/utils.js index efc0c359d3..699995e63f 100644 --- a/packages/server/src/integrations/utils.js +++ b/packages/server/src/integrations/utils.js @@ -1,19 +1,17 @@ const { DocumentTypes, SEPARATOR } = require("../db/utils") -const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}` - exports.isExternalTable = tableId => { return tableId.includes(DocumentTypes.DATASOURCE) } exports.buildExternalTableId = (datasourceId, tableName) => { - return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}` + return `${datasourceId}${SEPARATOR}${tableName}` } exports.breakExternalTableId = tableId => { - const parts = tableId.split(DOUBLE_SEPARATOR) + const parts = tableId.split(SEPARATOR) let tableName = parts.pop() - let datasourceId = parts.join(DOUBLE_SEPARATOR) + let datasourceId = parts.join(SEPARATOR) return { datasourceId, tableName } } diff --git a/packages/server/src/middleware/authorized.js b/packages/server/src/middleware/authorized.js index bd064f7e66..8ed4c41db7 100644 --- a/packages/server/src/middleware/authorized.js +++ b/packages/server/src/middleware/authorized.js @@ -14,52 +14,50 @@ const WEBHOOK_ENDPOINTS = new RegExp( ["webhooks/trigger", "webhooks/schema"].join("|") ) -module.exports = - (permType, permLevel = null) => - async (ctx, next) => { - // webhooks don't need authentication, each webhook unique - if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) { - return next() - } - - if (!ctx.user) { - return ctx.throw(403, "No user info found") - } - - // check general builder stuff, this middleware is a good way - // to find API endpoints which are builder focused - await builderMiddleware(ctx, permType) - - const isAuthed = ctx.isAuthenticated - const { basePermissions, permissions } = await getUserPermissions( - ctx.appId, - ctx.roleId - ) - - // builders for now have permission to do anything - // TODO: in future should consider separating permissions with an require("@budibase/auth").isClient check - let isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global - const isBuilderApi = permType === PermissionTypes.BUILDER - if (isBuilder) { - return next() - } else if (isBuilderApi && !isBuilder) { - return ctx.throw(403, "Not Authorized") - } - - if ( - hasResource(ctx) && - doesHaveResourcePermission(permissions, permLevel, ctx) - ) { - return next() - } - - if (!isAuthed) { - ctx.throw(403, "Session not authenticated") - } - - if (!doesHaveBasePermission(permType, permLevel, basePermissions)) { - ctx.throw(403, "User does not have permission") - } - +module.exports = (permType, permLevel = null) => async (ctx, next) => { + // webhooks don't need authentication, each webhook unique + if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) { return next() } + + if (!ctx.user) { + return ctx.throw(403, "No user info found") + } + + // check general builder stuff, this middleware is a good way + // to find API endpoints which are builder focused + await builderMiddleware(ctx, permType) + + const isAuthed = ctx.isAuthenticated + const { basePermissions, permissions } = await getUserPermissions( + ctx.appId, + ctx.roleId + ) + + // builders for now have permission to do anything + // TODO: in future should consider separating permissions with an require("@budibase/auth").isClient check + let isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global + const isBuilderApi = permType === PermissionTypes.BUILDER + if (isBuilder) { + return next() + } else if (isBuilderApi && !isBuilder) { + return ctx.throw(403, "Not Authorized") + } + + if ( + hasResource(ctx) && + doesHaveResourcePermission(permissions, permLevel, ctx) + ) { + return next() + } + + if (!isAuthed) { + ctx.throw(403, "Session not authenticated") + } + + if (!doesHaveBasePermission(permType, permLevel, basePermissions)) { + ctx.throw(403, "User does not have permission") + } + + return next() +} diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 683b7f8ef3..19d0afd560 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -1,5 +1,9 @@ -const { getAppId, setCookie, getCookie, clearCookie } = - require("@budibase/auth").utils +const { + getAppId, + setCookie, + getCookie, + clearCookie, +} = require("@budibase/auth").utils const { Cookies } = require("@budibase/auth").constants const { getRole } = require("@budibase/auth/roles") const { getGlobalSelf } = require("../utilities/workerRequests") diff --git a/packages/standard-components/manifest.json b/packages/standard-components/manifest.json index 24f910872b..6a5de3b8c2 100644 --- a/packages/standard-components/manifest.json +++ b/packages/standard-components/manifest.json @@ -135,6 +135,20 @@ "label": "Text", "key": "text" }, + { + "type": "select", + "label": "Button Type", + "key": "type", + "options": ["primary", "secondary", "cta", "warning"], + "defaultValue": "primary" + }, + { + "type": "select", + "label": "Size", + "key": "size", + "options": ["S", "M", "L", "XL"], + "defaultValue": "M" + }, { "type": "boolean", "label": "Disabled", diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte index e9a6d6e95e..d307b25256 100644 --- a/packages/standard-components/src/Button.svelte +++ b/packages/standard-components/src/Button.svelte @@ -7,31 +7,15 @@ export let disabled = false export let text = "" export let onClick + export let size = "M" + export let type = "primary" {text || ""} - - - + \ No newline at end of file diff --git a/packages/standard-components/src/forms/validation.js b/packages/standard-components/src/forms/validation.js index b1df80509f..ebdb3b3dab 100644 --- a/packages/standard-components/src/forms/validation.js +++ b/packages/standard-components/src/forms/validation.js @@ -90,17 +90,15 @@ const numericalConstraint = (constraint, error) => value => { return null } -const inclusionConstraint = - (options = []) => - value => { - if (value == null || value === "") { - return null - } - if (!options.includes(value)) { - return "Invalid value" - } +const inclusionConstraint = (options = []) => value => { + if (value == null || value === "") { return null } + if (!options.includes(value)) { + return "Invalid value" + } + return null +} const dateConstraint = (dateString, isEarliest) => { const dateLimit = Date.parse(dateString) diff --git a/packages/worker/src/api/controllers/admin/email.js b/packages/worker/src/api/controllers/admin/email.js index 6e16fd060c..c4b17ee980 100644 --- a/packages/worker/src/api/controllers/admin/email.js +++ b/packages/worker/src/api/controllers/admin/email.js @@ -5,8 +5,15 @@ const authPkg = require("@budibase/auth") const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name exports.sendEmail = async ctx => { - const { groupId, email, userId, purpose, contents, from, subject } = - ctx.request.body + const { + groupId, + email, + userId, + purpose, + contents, + from, + subject, + } = ctx.request.body let user if (userId) { const db = new CouchDB(GLOBAL_DB) diff --git a/packages/worker/src/api/controllers/admin/groups.js b/packages/worker/src/api/controllers/admin/groups.js index 330fb38282..8a70721431 100644 --- a/packages/worker/src/api/controllers/admin/groups.js +++ b/packages/worker/src/api/controllers/admin/groups.js @@ -1,6 +1,9 @@ const CouchDB = require("../../../db") -const { getGroupParams, generateGroupID, StaticDatabases } = - require("@budibase/auth").db +const { + getGroupParams, + generateGroupID, + StaticDatabases, +} = require("@budibase/auth").db const GLOBAL_DB = StaticDatabases.GLOBAL.name diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index 5b95b2808f..6afd4ecbfd 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -1,6 +1,9 @@ const CouchDB = require("../../../db") -const { generateGlobalUserID, getGlobalUserParams, StaticDatabases } = - require("@budibase/auth").db +const { + generateGlobalUserID, + getGlobalUserParams, + StaticDatabases, +} = require("@budibase/auth").db const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils const { UserStatus, EmailTemplatePurpose } = require("../../../constants") const { checkInviteCode } = require("../../../utilities/redis")
{query.name}
{capitalise(query.queryVerb)}
→