Merge branch 'develop' of github.com:Budibase/budibase into feature/mssql-plus
This commit is contained in:
commit
e6d05f1e90
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/auth",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"description": "Authentication middlewares for budibase builder and apps",
|
||||
"main": "src/index.js",
|
||||
"author": "Budibase",
|
||||
|
|
|
@ -6,6 +6,7 @@ exports.UserStatus = {
|
|||
exports.Cookies = {
|
||||
CurrentApp: "budibase:currentapp",
|
||||
Auth: "budibase:auth",
|
||||
Init: "budibase:init",
|
||||
OIDC_CONFIG: "budibase:oidc:config",
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"license": "AGPL-3.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"license": "AGPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -65,10 +65,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "^0.9.176-alpha.3",
|
||||
"@budibase/client": "^0.9.176-alpha.3",
|
||||
"@budibase/bbui": "^0.9.180-alpha.0",
|
||||
"@budibase/client": "^0.9.180-alpha.0",
|
||||
"@budibase/colorpicker": "1.1.2",
|
||||
"@budibase/string-templates": "^0.9.176-alpha.3",
|
||||
"@budibase/string-templates": "^0.9.180-alpha.0",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -8,10 +8,13 @@
|
|||
|
||||
let name
|
||||
let selectedTrigger
|
||||
let nameTouched = false
|
||||
let triggerVal
|
||||
export let webhookModal
|
||||
|
||||
$: instanceId = $database._id
|
||||
$: nameError =
|
||||
nameTouched && !name ? "Please specify a name for the automation." : null
|
||||
|
||||
async function createAutomation() {
|
||||
await automationStore.actions.create({
|
||||
|
@ -51,13 +54,18 @@
|
|||
confirmText="Save"
|
||||
size="M"
|
||||
onConfirm={createAutomation}
|
||||
disabled={!selectedTrigger}
|
||||
disabled={!selectedTrigger || !name}
|
||||
>
|
||||
<Body size="XS"
|
||||
>Please name your automation, then select a trigger. Every automation must
|
||||
start with a trigger.
|
||||
</Body>
|
||||
<Input bind:value={name} label="Name" />
|
||||
<Input
|
||||
bind:value={name}
|
||||
on:change={() => (nameTouched = true)}
|
||||
bind:error={nameError}
|
||||
label="Name"
|
||||
/>
|
||||
|
||||
<Layout noPadding>
|
||||
<Body size="S">Triggers</Body>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
Checkbox,
|
||||
} from "@budibase/bbui"
|
||||
import { store, automationStore, hostingStore } from "builderStore"
|
||||
import { admin } from "stores/portal"
|
||||
import { admin, auth } from "stores/portal"
|
||||
import { string, mixed, object } from "yup"
|
||||
import api, { get, post } from "builderStore/api"
|
||||
import analytics, { Events } from "analytics"
|
||||
|
@ -139,6 +139,7 @@
|
|||
}
|
||||
const userResp = await api.post(`/api/users/metadata/self`, user)
|
||||
await userResp.json()
|
||||
await auth.setInitInfo({})
|
||||
$goto(`/builder/app/${appJson.instance._id}`)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
@ -146,6 +147,16 @@
|
|||
submitting = false
|
||||
}
|
||||
}
|
||||
|
||||
function getModalTitle() {
|
||||
let title = "Create App"
|
||||
if (template.fromFile) {
|
||||
title = "Import App"
|
||||
} else if (template.key) {
|
||||
title = "Create app from template"
|
||||
}
|
||||
return title
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if showTemplateSelection}
|
||||
|
@ -172,7 +183,7 @@
|
|||
</ModalContent>
|
||||
{:else}
|
||||
<ModalContent
|
||||
title={template?.fromFile ? "Import app" : "Create app"}
|
||||
title={getModalTitle()}
|
||||
confirmText={template?.fromFile ? "Import app" : "Create app"}
|
||||
onConfirm={createNewApp}
|
||||
onCancel={inline ? () => (template = null) : null}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { isActive, redirect } from "@roxi/routify"
|
||||
import { isActive, redirect, params } from "@roxi/routify"
|
||||
import { admin, auth } from "stores/portal"
|
||||
import { onMount } from "svelte"
|
||||
|
||||
|
@ -47,6 +47,10 @@
|
|||
}
|
||||
|
||||
onMount(async () => {
|
||||
if ($params["?template"]) {
|
||||
await auth.setInitInfo({ init_template: $params["?template"] })
|
||||
}
|
||||
|
||||
await auth.checkAuth()
|
||||
await admin.init()
|
||||
|
||||
|
|
|
@ -184,9 +184,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
function createAppFromTemplateUrl(templateKey) {
|
||||
// validate the template key just to make sure
|
||||
const templateParts = templateKey.split("/")
|
||||
if (templateParts.length === 2 && templateParts[0] === "app") {
|
||||
template = {
|
||||
key: templateKey,
|
||||
}
|
||||
initiateAppCreation()
|
||||
} else {
|
||||
notifications.error("Your Template URL is invalid. Please try another.")
|
||||
}
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await apps.load()
|
||||
loaded = true
|
||||
// if the portal is loaded from an external URL with a template param
|
||||
const initInfo = await auth.getInitInfo()
|
||||
if (initInfo.init_template) {
|
||||
createAppFromTemplateUrl(initInfo.init_template)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -83,6 +83,13 @@ export function createAuthStore() {
|
|||
return {
|
||||
subscribe: store.subscribe,
|
||||
setOrganisation: setOrganisation,
|
||||
getInitInfo: async () => {
|
||||
const response = await api.get(`/api/global/auth/init`)
|
||||
return await response.json()
|
||||
},
|
||||
setInitInfo: async info => {
|
||||
await api.post(`/api/global/auth/init`, info)
|
||||
},
|
||||
checkQueryString: async () => {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
if (urlParams.has("tenantId")) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"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": "^0.9.176-alpha.3",
|
||||
"@budibase/bbui": "^0.9.180-alpha.0",
|
||||
"@budibase/standard-components": "^0.9.139",
|
||||
"@budibase/string-templates": "^0.9.176-alpha.3",
|
||||
"@budibase/string-templates": "^0.9.180-alpha.0",
|
||||
"regexparam": "^1.3.0",
|
||||
"shortid": "^2.2.15",
|
||||
"svelte-spa-router": "^3.0.5"
|
||||
|
|
|
@ -59,11 +59,10 @@ export const createDataSourceStore = () => {
|
|||
|
||||
// Emit this as a window event, so parent screens which are iframing us in
|
||||
// can also invalidate the same datasource
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("invalidate-datasource", {
|
||||
window.parent.postMessage({
|
||||
type: "close-screen-modal",
|
||||
detail: { dataSourceId },
|
||||
})
|
||||
)
|
||||
|
||||
let invalidations = [dataSourceId]
|
||||
|
||||
|
|
|
@ -34,11 +34,6 @@ const createNotificationStore = () => {
|
|||
icon,
|
||||
},
|
||||
})
|
||||
// window.dispatchEvent(
|
||||
// new CustomEvent("notification", {
|
||||
// detail: { message, type, icon },
|
||||
// })
|
||||
// )
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ const changeFormStepHandler = async (action, context) => {
|
|||
const closeScreenModalHandler = () => {
|
||||
// Emit this as a window event, so parent screens which are iframing us in
|
||||
// can close the modal
|
||||
window.dispatchEvent(new Event("close-screen-modal"))
|
||||
window.parent.postMessage({ type: "close-screen-modal" })
|
||||
}
|
||||
|
||||
const updateStateHandler = action => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
|
@ -68,9 +68,9 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.176-alpha.3",
|
||||
"@budibase/client": "^0.9.176-alpha.3",
|
||||
"@budibase/string-templates": "^0.9.176-alpha.3",
|
||||
"@budibase/auth": "^0.9.180-alpha.0",
|
||||
"@budibase/client": "^0.9.180-alpha.0",
|
||||
"@budibase/string-templates": "^0.9.180-alpha.0",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
"@koa/router": "8.0.0",
|
||||
"@sendgrid/mail": "7.1.1",
|
||||
|
|
|
@ -23,9 +23,6 @@ function formatResponse(resp) {
|
|||
try {
|
||||
resp = JSON.parse(resp)
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"Error parsing JSON response. Returning string in array instead."
|
||||
)
|
||||
resp = { response: resp }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ const { generateWebhookID, getWebhookParams } = require("../../db/utils")
|
|||
const toJsonSchema = require("to-json-schema")
|
||||
const validate = require("jsonschema").validate
|
||||
const triggers = require("../../automations/triggers")
|
||||
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||
|
||||
const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema"
|
||||
|
||||
|
@ -76,7 +77,9 @@ exports.buildSchema = async ctx => {
|
|||
}
|
||||
|
||||
exports.trigger = async ctx => {
|
||||
const db = new CouchDB(ctx.params.instance)
|
||||
const prodAppId = getDeployedAppID(ctx.params.instance)
|
||||
try {
|
||||
const db = new CouchDB(prodAppId)
|
||||
const webhook = await db.get(ctx.params.id)
|
||||
// validate against the schema
|
||||
if (webhook.bodySchema) {
|
||||
|
@ -89,11 +92,19 @@ exports.trigger = async ctx => {
|
|||
await triggers.externalTrigger(target, {
|
||||
body: ctx.request.body,
|
||||
...ctx.request.body,
|
||||
appId: ctx.params.instance,
|
||||
appId: prodAppId,
|
||||
})
|
||||
}
|
||||
ctx.status = 200
|
||||
ctx.body = {
|
||||
message: "Webhook trigger fired successfully",
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.status === 404) {
|
||||
ctx.status = 200
|
||||
ctx.body = {
|
||||
message: "Application not deployed yet.",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,19 +85,6 @@ exports.run = async function ({ inputs }) {
|
|||
const request = {
|
||||
method: requestMethod,
|
||||
}
|
||||
if (
|
||||
requestBody &&
|
||||
requestBody.length !== 0 &&
|
||||
BODY_REQUESTS.indexOf(requestMethod) !== -1
|
||||
) {
|
||||
request.body =
|
||||
typeof requestBody === "string"
|
||||
? requestBody
|
||||
: JSON.stringify(requestBody)
|
||||
request.headers = {
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
try {
|
||||
const customHeaders =
|
||||
|
@ -110,6 +97,19 @@ exports.run = async function ({ inputs }) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
requestBody &&
|
||||
requestBody.length !== 0 &&
|
||||
BODY_REQUESTS.indexOf(requestMethod) !== -1
|
||||
) {
|
||||
request.body =
|
||||
typeof requestBody === "string"
|
||||
? requestBody
|
||||
: JSON.stringify(requestBody)
|
||||
request.headers = {
|
||||
...request.headers,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -122,7 +122,7 @@ exports.run = async function ({ inputs }) {
|
|||
return {
|
||||
httpStatus: status,
|
||||
response: message,
|
||||
success: status === 200,
|
||||
success: status >= 200 && status <= 206,
|
||||
}
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
|
|
|
@ -6,6 +6,7 @@ const { queue } = require("./bullboard")
|
|||
const newid = require("../db/newid")
|
||||
const { updateEntityMetadata } = require("../utilities")
|
||||
const { MetadataTypes } = require("../constants")
|
||||
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||
|
||||
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
||||
const CRON_STEP_ID = definitions.CRON.stepId
|
||||
|
@ -150,9 +151,13 @@ exports.checkForWebhooks = async ({ appId, oldAuto, newAuto }) => {
|
|||
await webhooks.save(ctx)
|
||||
const id = ctx.body.webhook._id
|
||||
newTrigger.webhookId = id
|
||||
// the app ID has to be development for this endpoint
|
||||
// it can only be used when building the app
|
||||
// but the trigger endpoint will always be used in production
|
||||
const prodAppId = getDeployedAppID(appId)
|
||||
newTrigger.inputs = {
|
||||
schemaUrl: `api/webhooks/schema/${appId}/${id}`,
|
||||
triggerUrl: `api/webhooks/trigger/${appId}/${id}`,
|
||||
triggerUrl: `api/webhooks/trigger/${prodAppId}/${id}`,
|
||||
}
|
||||
}
|
||||
return newAuto
|
||||
|
|
|
@ -142,13 +142,11 @@ module RestModule {
|
|||
}
|
||||
|
||||
async parseResponse(response: any) {
|
||||
switch (this.headers.Accept) {
|
||||
case "application/json":
|
||||
const contentType = response.headers.get("content-type")
|
||||
if (contentType && contentType.indexOf("application/json") !== -1) {
|
||||
return await response.json()
|
||||
case "text/html":
|
||||
} else {
|
||||
return await response.text()
|
||||
default:
|
||||
return await response.json()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +189,7 @@ module RestModule {
|
|||
}
|
||||
|
||||
const response = await fetch(this.getUrl(path, queryString), {
|
||||
method: "POST",
|
||||
method: "PUT",
|
||||
headers: this.headers,
|
||||
body: JSON.stringify(json),
|
||||
})
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
jest.mock("node-fetch", () =>
|
||||
jest.fn(() => ({ json: jest.fn(), text: jest.fn() }))
|
||||
jest.fn(() => ({
|
||||
headers: {
|
||||
get: () => ["application/json"]
|
||||
},
|
||||
json: jest.fn(),
|
||||
text: jest.fn()
|
||||
}))
|
||||
)
|
||||
const fetch = require("node-fetch")
|
||||
const RestIntegration = require("../rest")
|
||||
|
|
|
@ -5,20 +5,17 @@ const {
|
|||
doesHaveBasePermission,
|
||||
} = require("@budibase/auth/permissions")
|
||||
const builderMiddleware = require("./builder")
|
||||
const { isWebhookEndpoint } = require("./utils")
|
||||
|
||||
function hasResource(ctx) {
|
||||
return ctx.resourceId != null
|
||||
}
|
||||
|
||||
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)) {
|
||||
if (isWebhookEndpoint(ctx)) {
|
||||
return next()
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ const { isUserInAppTenant } = require("@budibase/auth/tenancy")
|
|||
const { getCachedSelf } = require("../utilities/global")
|
||||
const CouchDB = require("../db")
|
||||
const env = require("../environment")
|
||||
const { isWebhookEndpoint } = require("./utils")
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
// try to get the appID from the request
|
||||
|
@ -38,6 +39,7 @@ module.exports = async (ctx, next) => {
|
|||
// deny access to application preview
|
||||
if (
|
||||
isDevAppID(requestAppId) &&
|
||||
!isWebhookEndpoint(ctx) &&
|
||||
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
|
||||
) {
|
||||
clearCookie(ctx, Cookies.CurrentApp)
|
||||
|
|
|
@ -2,6 +2,10 @@ const CouchDB = require("../db")
|
|||
const usageQuota = require("../utilities/usageQuota")
|
||||
const env = require("../environment")
|
||||
const { getTenantId } = require("@budibase/auth/tenancy")
|
||||
const {
|
||||
isExternalTable,
|
||||
isRowId: isExternalRowId,
|
||||
} = require("../integrations/utils")
|
||||
|
||||
// tenants without limits
|
||||
const EXCLUDED_TENANTS = ["bb", "default", "bbtest", "bbstaging"]
|
||||
|
@ -46,14 +50,24 @@ module.exports = async (ctx, next) => {
|
|||
}
|
||||
// post request could be a save of a pre-existing entry
|
||||
if (ctx.request.body && ctx.request.body._id && ctx.request.body._rev) {
|
||||
const usageId = ctx.request.body._id
|
||||
try {
|
||||
if (ctx.appId) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
await db.get(ctx.request.body._id)
|
||||
await db.get(usageId)
|
||||
}
|
||||
return next()
|
||||
} catch (err) {
|
||||
ctx.throw(404, `${ctx.request.body._id} does not exist`)
|
||||
if (
|
||||
isExternalTable(usageId) ||
|
||||
(ctx.request.body.tableId &&
|
||||
isExternalTable(ctx.request.body.tableId)) ||
|
||||
isExternalRowId(usageId)
|
||||
) {
|
||||
return next()
|
||||
} else {
|
||||
ctx.throw(404, `${usageId} does not exist`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
const WEBHOOK_ENDPOINTS = new RegExp(
|
||||
["webhooks/trigger", "webhooks/schema"].join("|")
|
||||
)
|
||||
|
||||
exports.isWebhookEndpoint = ctx => {
|
||||
return WEBHOOK_ENDPOINTS.test(ctx.request.url)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "0.9.176-alpha.3",
|
||||
"version": "0.9.180-alpha.0",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
|
@ -29,8 +29,8 @@
|
|||
"author": "Budibase",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
"@budibase/auth": "^0.9.176-alpha.3",
|
||||
"@budibase/string-templates": "^0.9.176-alpha.3",
|
||||
"@budibase/auth": "^0.9.180-alpha.0",
|
||||
"@budibase/string-templates": "^0.9.180-alpha.0",
|
||||
"@koa/router": "^8.0.0",
|
||||
"@sentry/node": "^6.0.0",
|
||||
"@techpass/passport-openidconnect": "^0.3.0",
|
||||
|
|
|
@ -77,6 +77,17 @@ exports.authenticate = async (ctx, next) => {
|
|||
})(ctx, next)
|
||||
}
|
||||
|
||||
exports.setInitInfo = ctx => {
|
||||
const initInfo = ctx.request.body
|
||||
setCookie(ctx, initInfo, Cookies.Init)
|
||||
ctx.status = 200
|
||||
}
|
||||
|
||||
exports.getInitInfo = ctx => {
|
||||
const initInfo = getCookie(ctx, Cookies.Init)
|
||||
ctx.body = initInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the user password, used as part of a forgotten password flow.
|
||||
*/
|
||||
|
|
|
@ -56,6 +56,8 @@ router
|
|||
authController.resetUpdate
|
||||
)
|
||||
.post("/api/global/auth/logout", authController.logout)
|
||||
.post("/api/global/auth/init", authController.setInitInfo)
|
||||
.get("/api/global/auth/init", authController.getInitInfo)
|
||||
.get(
|
||||
"/api/global/auth/:tenantId/google",
|
||||
updateTenant,
|
||||
|
|
Loading…
Reference in New Issue