Merge branch 'feature/opinionated-sql' of github.com:Budibase/budibase into feature/opinionated-sql
This commit is contained in:
commit
1014260ad5
|
@ -2,21 +2,23 @@ import { store } from "./index"
|
||||||
import { get as svelteGet } from "svelte/store"
|
import { get as svelteGet } from "svelte/store"
|
||||||
import { removeCookie, Cookies } from "./cookies"
|
import { removeCookie, Cookies } from "./cookies"
|
||||||
|
|
||||||
const apiCall =
|
const apiCall = method => async (
|
||||||
method =>
|
url,
|
||||||
async (url, body, headers = { "Content-Type": "application/json" }) => {
|
body,
|
||||||
headers["x-budibase-app-id"] = svelteGet(store).appId
|
headers = { "Content-Type": "application/json" }
|
||||||
const json = headers["Content-Type"] === "application/json"
|
) => {
|
||||||
const resp = await fetch(url, {
|
headers["x-budibase-app-id"] = svelteGet(store).appId
|
||||||
method: method,
|
const json = headers["Content-Type"] === "application/json"
|
||||||
body: json ? JSON.stringify(body) : body,
|
const resp = await fetch(url, {
|
||||||
headers,
|
method: method,
|
||||||
})
|
body: json ? JSON.stringify(body) : body,
|
||||||
if (resp.status === 403) {
|
headers,
|
||||||
removeCookie(Cookies.Auth)
|
})
|
||||||
}
|
if (resp.status === 403) {
|
||||||
return resp
|
removeCookie(Cookies.Auth)
|
||||||
}
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
export const post = apiCall("POST")
|
export const post = apiCall("POST")
|
||||||
export const get = apiCall("GET")
|
export const get = apiCall("GET")
|
||||||
|
|
|
@ -100,10 +100,9 @@ const automationActions = store => ({
|
||||||
},
|
},
|
||||||
deleteAutomationBlock: block => {
|
deleteAutomationBlock: block => {
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
const idx =
|
const idx = state.selectedAutomation.automation.definition.steps.findIndex(
|
||||||
state.selectedAutomation.automation.definition.steps.findIndex(
|
x => x.id === block.id
|
||||||
x => x.id === block.id
|
)
|
||||||
)
|
|
||||||
state.selectedAutomation.deleteBlock(block.id)
|
state.selectedAutomation.deleteBlock(block.id)
|
||||||
|
|
||||||
// Select next closest step
|
// Select next closest step
|
||||||
|
|
|
@ -53,7 +53,9 @@
|
||||||
bind:hideAutocolumns
|
bind:hideAutocolumns
|
||||||
{loading}
|
{loading}
|
||||||
>
|
>
|
||||||
<CreateColumnButton />
|
{#if isInternal}
|
||||||
|
<CreateColumnButton />
|
||||||
|
{/if}
|
||||||
{#if schema && Object.keys(schema).length > 0}
|
{#if schema && Object.keys(schema).length > 0}
|
||||||
{#if !isUsersTable}
|
{#if !isUsersTable}
|
||||||
<CreateRowButton
|
<CreateRowButton
|
||||||
|
|
|
@ -9,7 +9,11 @@
|
||||||
import CreateEditRow from "./modals/CreateEditRow.svelte"
|
import CreateEditRow from "./modals/CreateEditRow.svelte"
|
||||||
import CreateEditUser from "./modals/CreateEditUser.svelte"
|
import CreateEditUser from "./modals/CreateEditUser.svelte"
|
||||||
import CreateEditColumn from "./modals/CreateEditColumn.svelte"
|
import CreateEditColumn from "./modals/CreateEditColumn.svelte"
|
||||||
import { TableNames, UNEDITABLE_USER_FIELDS, BUDIBASE_INTERNAL_DB } from "constants"
|
import {
|
||||||
|
TableNames,
|
||||||
|
UNEDITABLE_USER_FIELDS,
|
||||||
|
BUDIBASE_INTERNAL_DB,
|
||||||
|
} from "constants"
|
||||||
import RoleCell from "./cells/RoleCell.svelte"
|
import RoleCell from "./cells/RoleCell.svelte"
|
||||||
|
|
||||||
export let schema = {}
|
export let schema = {}
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClickQuery(query) {
|
function onClickQuery(query) {
|
||||||
if ($queries.selected === query._id) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
queries.select(query)
|
queries.select(query)
|
||||||
$goto(`./datasource/${query.datasourceId}/${query._id}`)
|
$goto(`./datasource/${query.datasourceId}/${query._id}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon } from "@budibase/bbui"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a target="_blank" href="https://github.com/Budibase/budibase/discussions">
|
<a target="_blank" href="https://github.com/Budibase/budibase/discussions">
|
||||||
<Icon hoverable name="Help" size="XXL" />
|
<Icon hoverable name="Help" size="XXL" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -14,4 +14,4 @@
|
||||||
right: var(--spacing-m);
|
right: var(--spacing-m);
|
||||||
border-radius: 55%;
|
border-radius: 55%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -59,7 +59,9 @@
|
||||||
<section>
|
<section>
|
||||||
<Heading size="XS">Columns</Heading>
|
<Heading size="XS">Columns</Heading>
|
||||||
<ul>
|
<ul>
|
||||||
{#each context.filter( context => context.readableBinding.match(searchRgx) ) as { readableBinding }}
|
{#each context.filter(context =>
|
||||||
|
context.readableBinding.match(searchRgx)
|
||||||
|
) as { readableBinding }}
|
||||||
<li
|
<li
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
value = addToText(value, getCaretPosition(), readableBinding)
|
value = addToText(value, getCaretPosition(), readableBinding)
|
||||||
|
@ -75,7 +77,9 @@
|
||||||
<section>
|
<section>
|
||||||
<Heading size="XS">Components</Heading>
|
<Heading size="XS">Components</Heading>
|
||||||
<ul>
|
<ul>
|
||||||
{#each instance.filter( instance => instance.readableBinding.match(searchRgx) ) as { readableBinding }}
|
{#each instance.filter(instance =>
|
||||||
|
instance.readableBinding.match(searchRgx)
|
||||||
|
) as { readableBinding }}
|
||||||
<li on:click={() => addToText(readableBinding)}>
|
<li on:click={() => addToText(readableBinding)}>
|
||||||
{readableBinding}
|
{readableBinding}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -49,7 +49,9 @@
|
||||||
<div class="section">
|
<div class="section">
|
||||||
{#each categories as [categoryName, bindings]}
|
{#each categories as [categoryName, bindings]}
|
||||||
<Heading size="XS">{categoryName}</Heading>
|
<Heading size="XS">{categoryName}</Heading>
|
||||||
{#each bindings.filter( binding => binding.label.match(searchRgx) ) as binding}
|
{#each bindings.filter(binding =>
|
||||||
|
binding.label.match(searchRgx)
|
||||||
|
) as binding}
|
||||||
<div
|
<div
|
||||||
class="binding"
|
class="binding"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
|
|
@ -103,9 +103,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchQueryDefinition(query) {
|
function fetchQueryDefinition(query) {
|
||||||
const source = $datasources.list.find(
|
const source = $datasources.list.find(ds => ds._id === query.datasourceId)
|
||||||
ds => ds._id === query.datasourceId
|
.source
|
||||||
).source
|
|
||||||
return $integrations[source].query[query.queryVerb]
|
return $integrations[source].query[query.queryVerb]
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
function fetchQueryDefinition(query) {
|
function fetchQueryDefinition(query) {
|
||||||
const source = $datasources.list.find(
|
const source = $datasources.list.find(ds => ds._id === query.datasourceId)
|
||||||
ds => ds._id === query.datasourceId
|
.source
|
||||||
).source
|
|
||||||
return $integrations[source].query[query.queryVerb]
|
return $integrations[source].query[query.queryVerb]
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { goto, beforeUrlChange } from "@roxi/routify"
|
import { goto, beforeUrlChange } from "@roxi/routify"
|
||||||
import { Button, Heading, Body, Divider, Layout } from "@budibase/bbui"
|
import { Button, Heading, Body, Divider, Layout } from "@budibase/bbui"
|
||||||
import {
|
import { datasources, integrations, queries, tables } from "stores/backend"
|
||||||
datasources,
|
|
||||||
integrations,
|
|
||||||
queries,
|
|
||||||
tables,
|
|
||||||
} from "stores/backend"
|
|
||||||
import { notifications } from "@budibase/bbui"
|
import { notifications } from "@budibase/bbui"
|
||||||
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
|
import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte"
|
||||||
import ICONS from "components/backend/DatasourceNavigator/icons"
|
import ICONS from "components/backend/DatasourceNavigator/icons"
|
||||||
|
@ -100,11 +95,16 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<Body>
|
<Body>
|
||||||
This datasource can determine tables automatically. Budibase can fetch your tables directly from the database and you can use them without having to write any queries at all.
|
This datasource can determine tables automatically. Budibase can fetch
|
||||||
|
your tables directly from the database and you can use them without
|
||||||
|
having to write any queries at all.
|
||||||
</Body>
|
</Body>
|
||||||
<div class="query-list">
|
<div class="query-list">
|
||||||
{#each Object.keys(datasource.entities) as entity}
|
{#each Object.keys(datasource.entities) as entity}
|
||||||
<div class="query-list-item" on:click={() => onClickTable(datasource.entities[entity])}>
|
<div
|
||||||
|
class="query-list-item"
|
||||||
|
on:click={() => onClickTable(datasource.entities[entity])}
|
||||||
|
>
|
||||||
<p class="query-name">{entity}</p>
|
<p class="query-name">{entity}</p>
|
||||||
<p>Primary Key: {datasource.entities[entity].primary}</p>
|
<p>Primary Key: {datasource.entities[entity].primary}</p>
|
||||||
<p>→</p>
|
<p>→</p>
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
import { Button, Heading, Body, Layout, Modal } from "@budibase/bbui"
|
import { Button, Heading, Body, Layout, Modal } from "@budibase/bbui"
|
||||||
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
import CreateTableModal from "components/backend/TableNavigator/modals/CreateTableModal.svelte"
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
|
@ -12,14 +10,9 @@
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<Heading>
|
<Heading>Budibase Internal DB</Heading>
|
||||||
Budibase Internal DB
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Body>
|
<div>
|
||||||
Stuff about the internal table
|
<Button cta on:click={modal.show}>Create new table</Button>
|
||||||
</Body>
|
</div>
|
||||||
|
</Layout>
|
||||||
<Button cta on:click={modal.show}>Create new table</Button>
|
|
||||||
|
|
||||||
</Layout>
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { queries } from "./"
|
import { queries, tables, views } from "./"
|
||||||
import api from "../../builderStore/api"
|
import api from "../../builderStore/api"
|
||||||
|
|
||||||
export const INITIAL_DATASOURCE_VALUES = {
|
export const INITIAL_DATASOURCE_VALUES = {
|
||||||
|
@ -26,7 +26,12 @@ export function createDatasourcesStore() {
|
||||||
},
|
},
|
||||||
select: async datasourceId => {
|
select: async datasourceId => {
|
||||||
update(state => ({ ...state, selected: datasourceId }))
|
update(state => ({ ...state, selected: datasourceId }))
|
||||||
queries.update(state => ({ ...state, selected: null }))
|
queries.unselect()
|
||||||
|
tables.unselect()
|
||||||
|
views.unselect()
|
||||||
|
},
|
||||||
|
unselect: () => {
|
||||||
|
update(state => ({ ...state, selected: null }))
|
||||||
},
|
},
|
||||||
updateSchema: async datasource => {
|
updateSchema: async datasource => {
|
||||||
let url = `/api/datasources/${datasource._id}/schema`
|
let url = `/api/datasources/${datasource._id}/schema`
|
||||||
|
|
|
@ -6,4 +6,4 @@ export { permissions } from "./permissions"
|
||||||
export { roles } from "./roles"
|
export { roles } from "./roles"
|
||||||
export { datasources } from "./datasources"
|
export { datasources } from "./datasources"
|
||||||
export { integrations } from "./integrations"
|
export { integrations } from "./integrations"
|
||||||
export { queries } from "./queries"
|
export { queries } from "./queries"
|
||||||
|
|
|
@ -55,10 +55,6 @@ export function createQueriesStore() {
|
||||||
},
|
},
|
||||||
select: query => {
|
select: query => {
|
||||||
update(state => ({ ...state, selected: query._id }))
|
update(state => ({ ...state, selected: query._id }))
|
||||||
datasources.update(state => ({
|
|
||||||
...state,
|
|
||||||
selected: query.datasourceId,
|
|
||||||
}))
|
|
||||||
tables.update(state => ({
|
tables.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
selected: null,
|
selected: null,
|
||||||
|
@ -66,10 +62,6 @@ export function createQueriesStore() {
|
||||||
},
|
},
|
||||||
unselect: () => {
|
unselect: () => {
|
||||||
update(state => ({ ...state, selected: null }))
|
update(state => ({ ...state, selected: null }))
|
||||||
datasources.update(state => ({
|
|
||||||
...state,
|
|
||||||
selected: null,
|
|
||||||
}))
|
|
||||||
},
|
},
|
||||||
delete: async query => {
|
delete: async query => {
|
||||||
const response = await api.delete(
|
const response = await api.delete(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { views, queries } from "./"
|
import { views, queries, datasources } from "./"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
|
||||||
|
@ -25,8 +25,9 @@ export function createTablesStore() {
|
||||||
selected: table,
|
selected: table,
|
||||||
draft: cloneDeep(table),
|
draft: cloneDeep(table),
|
||||||
}))
|
}))
|
||||||
views.select({ name: table._id })
|
views.unselect()
|
||||||
queries.unselect()
|
queries.unselect()
|
||||||
|
datasources.unselect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +71,12 @@ export function createTablesStore() {
|
||||||
update,
|
update,
|
||||||
fetch,
|
fetch,
|
||||||
select,
|
select,
|
||||||
|
unselect: () => {
|
||||||
|
update(state => ({
|
||||||
|
...state,
|
||||||
|
selected: null,
|
||||||
|
}))
|
||||||
|
},
|
||||||
save,
|
save,
|
||||||
init: async () => {
|
init: async () => {
|
||||||
const response = await api.get("/api/tables")
|
const response = await api.get("/api/tables")
|
||||||
|
|
|
@ -9,7 +9,8 @@ export const SOME_QUERY = {
|
||||||
queryVerb: "read",
|
queryVerb: "read",
|
||||||
schema: {},
|
schema: {},
|
||||||
name: "Speakers",
|
name: "Speakers",
|
||||||
_id: "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f",
|
_id:
|
||||||
|
"query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f",
|
||||||
_rev: "2-941f8699eb0adf995f8bd59c99203b26",
|
_rev: "2-941f8699eb0adf995f8bd59c99203b26",
|
||||||
readable: true,
|
readable: true,
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,8 @@ export const SAVE_QUERY_RESPONSE = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
name: "Speakers",
|
name: "Speakers",
|
||||||
_id: "query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f",
|
_id:
|
||||||
|
"query_datasource_04b003a7b4a8428eadd3bb2f7eae0255_bcb8ffc6fcbc484e8d63121fc0bf986f",
|
||||||
_rev: "3-5a64adef494b1e9c793dc91b51ce73c6",
|
_rev: "3-5a64adef494b1e9c793dc91b51ce73c6",
|
||||||
readable: true,
|
readable: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { tables } from "./"
|
import { tables, datasources, queries } from "./"
|
||||||
import api from "builderStore/api"
|
import api from "builderStore/api"
|
||||||
|
|
||||||
export function createViewsStore() {
|
export function createViewsStore() {
|
||||||
|
@ -10,11 +10,20 @@ export function createViewsStore() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
|
update,
|
||||||
select: async view => {
|
select: async view => {
|
||||||
update(state => ({
|
update(state => ({
|
||||||
...state,
|
...state,
|
||||||
selected: view,
|
selected: view,
|
||||||
}))
|
}))
|
||||||
|
queries.unselect()
|
||||||
|
datasources.unselect()
|
||||||
|
},
|
||||||
|
unselect: () => {
|
||||||
|
update(state => ({
|
||||||
|
...state,
|
||||||
|
selected: null,
|
||||||
|
}))
|
||||||
},
|
},
|
||||||
delete: async view => {
|
delete: async view => {
|
||||||
await api.delete(`/api/views/${view}`)
|
await api.delete(`/api/views/${view}`)
|
||||||
|
|
|
@ -2,7 +2,8 @@ const { Client } = require("@elastic/elasticsearch")
|
||||||
const { QUERY_TYPES, FIELD_TYPES } = require("./Integration")
|
const { QUERY_TYPES, FIELD_TYPES } = require("./Integration")
|
||||||
|
|
||||||
const SCHEMA = {
|
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:
|
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.",
|
"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",
|
friendlyName: "ElasticSearch",
|
||||||
|
|
|
@ -14,52 +14,50 @@ const WEBHOOK_ENDPOINTS = new RegExp(
|
||||||
["webhooks/trigger", "webhooks/schema"].join("|")
|
["webhooks/trigger", "webhooks/schema"].join("|")
|
||||||
)
|
)
|
||||||
|
|
||||||
module.exports =
|
module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
||||||
(permType, permLevel = null) =>
|
// webhooks don't need authentication, each webhook unique
|
||||||
async (ctx, next) => {
|
if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) {
|
||||||
// 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()
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
const { getAppId, setCookie, getCookie, clearCookie } =
|
const {
|
||||||
require("@budibase/auth").utils
|
getAppId,
|
||||||
|
setCookie,
|
||||||
|
getCookie,
|
||||||
|
clearCookie,
|
||||||
|
} = require("@budibase/auth").utils
|
||||||
const { Cookies } = require("@budibase/auth").constants
|
const { Cookies } = require("@budibase/auth").constants
|
||||||
const { getRole } = require("@budibase/auth/roles")
|
const { getRole } = require("@budibase/auth/roles")
|
||||||
const { getGlobalSelf } = require("../utilities/workerRequests")
|
const { getGlobalSelf } = require("../utilities/workerRequests")
|
||||||
|
|
|
@ -90,17 +90,15 @@ const numericalConstraint = (constraint, error) => value => {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const inclusionConstraint =
|
const inclusionConstraint = (options = []) => value => {
|
||||||
(options = []) =>
|
if (value == null || value === "") {
|
||||||
value => {
|
|
||||||
if (value == null || value === "") {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
if (!options.includes(value)) {
|
|
||||||
return "Invalid value"
|
|
||||||
}
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
if (!options.includes(value)) {
|
||||||
|
return "Invalid value"
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const dateConstraint = (dateString, isEarliest) => {
|
const dateConstraint = (dateString, isEarliest) => {
|
||||||
const dateLimit = Date.parse(dateString)
|
const dateLimit = Date.parse(dateString)
|
||||||
|
|
|
@ -5,8 +5,15 @@ const authPkg = require("@budibase/auth")
|
||||||
const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name
|
const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name
|
||||||
|
|
||||||
exports.sendEmail = async ctx => {
|
exports.sendEmail = async ctx => {
|
||||||
const { groupId, email, userId, purpose, contents, from, subject } =
|
const {
|
||||||
ctx.request.body
|
groupId,
|
||||||
|
email,
|
||||||
|
userId,
|
||||||
|
purpose,
|
||||||
|
contents,
|
||||||
|
from,
|
||||||
|
subject,
|
||||||
|
} = ctx.request.body
|
||||||
let user
|
let user
|
||||||
if (userId) {
|
if (userId) {
|
||||||
const db = new CouchDB(GLOBAL_DB)
|
const db = new CouchDB(GLOBAL_DB)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const { getGroupParams, generateGroupID, StaticDatabases } =
|
const {
|
||||||
require("@budibase/auth").db
|
getGroupParams,
|
||||||
|
generateGroupID,
|
||||||
|
StaticDatabases,
|
||||||
|
} = require("@budibase/auth").db
|
||||||
|
|
||||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
const CouchDB = require("../../../db")
|
const CouchDB = require("../../../db")
|
||||||
const { generateGlobalUserID, getGlobalUserParams, StaticDatabases } =
|
const {
|
||||||
require("@budibase/auth").db
|
generateGlobalUserID,
|
||||||
|
getGlobalUserParams,
|
||||||
|
StaticDatabases,
|
||||||
|
} = require("@budibase/auth").db
|
||||||
const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils
|
const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils
|
||||||
const { UserStatus, EmailTemplatePurpose } = require("../../../constants")
|
const { UserStatus, EmailTemplatePurpose } = require("../../../constants")
|
||||||
const { checkInviteCode } = require("../../../utilities/redis")
|
const { checkInviteCode } = require("../../../utilities/redis")
|
||||||
|
|
Loading…
Reference in New Issue