Merge pull request #3239 from Budibase/fix/mike-various
Various fixes for recent issues
This commit is contained in:
commit
4d6b63b537
|
@ -8,10 +8,13 @@
|
||||||
|
|
||||||
let name
|
let name
|
||||||
let selectedTrigger
|
let selectedTrigger
|
||||||
|
let nameTouched = false
|
||||||
let triggerVal
|
let triggerVal
|
||||||
export let webhookModal
|
export let webhookModal
|
||||||
|
|
||||||
$: instanceId = $database._id
|
$: instanceId = $database._id
|
||||||
|
$: nameError =
|
||||||
|
nameTouched && !name ? "Please specify a name for the automation." : null
|
||||||
|
|
||||||
async function createAutomation() {
|
async function createAutomation() {
|
||||||
await automationStore.actions.create({
|
await automationStore.actions.create({
|
||||||
|
@ -51,13 +54,18 @@
|
||||||
confirmText="Save"
|
confirmText="Save"
|
||||||
size="M"
|
size="M"
|
||||||
onConfirm={createAutomation}
|
onConfirm={createAutomation}
|
||||||
disabled={!selectedTrigger}
|
disabled={!selectedTrigger || !name}
|
||||||
>
|
>
|
||||||
<Body size="XS"
|
<Body size="XS"
|
||||||
>Please name your automation, then select a trigger. Every automation must
|
>Please name your automation, then select a trigger. Every automation must
|
||||||
start with a trigger.
|
start with a trigger.
|
||||||
</Body>
|
</Body>
|
||||||
<Input bind:value={name} label="Name" />
|
<Input
|
||||||
|
bind:value={name}
|
||||||
|
on:change={() => (nameTouched = true)}
|
||||||
|
bind:error={nameError}
|
||||||
|
label="Name"
|
||||||
|
/>
|
||||||
|
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
<Body size="S">Triggers</Body>
|
<Body size="S">Triggers</Body>
|
||||||
|
|
|
@ -23,9 +23,6 @@ function formatResponse(resp) {
|
||||||
try {
|
try {
|
||||||
resp = JSON.parse(resp)
|
resp = JSON.parse(resp)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(
|
|
||||||
"Error parsing JSON response. Returning string in array instead."
|
|
||||||
)
|
|
||||||
resp = { response: resp }
|
resp = { response: resp }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ const { generateWebhookID, getWebhookParams } = require("../../db/utils")
|
||||||
const toJsonSchema = require("to-json-schema")
|
const toJsonSchema = require("to-json-schema")
|
||||||
const validate = require("jsonschema").validate
|
const validate = require("jsonschema").validate
|
||||||
const triggers = require("../../automations/triggers")
|
const triggers = require("../../automations/triggers")
|
||||||
|
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||||
|
|
||||||
const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema"
|
const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema"
|
||||||
|
|
||||||
|
@ -76,24 +77,34 @@ exports.buildSchema = async ctx => {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.trigger = async ctx => {
|
exports.trigger = async ctx => {
|
||||||
const db = new CouchDB(ctx.params.instance)
|
const prodAppId = getDeployedAppID(ctx.params.instance)
|
||||||
const webhook = await db.get(ctx.params.id)
|
try {
|
||||||
// validate against the schema
|
const db = new CouchDB(prodAppId)
|
||||||
if (webhook.bodySchema) {
|
const webhook = await db.get(ctx.params.id)
|
||||||
validate(ctx.request.body, webhook.bodySchema)
|
// validate against the schema
|
||||||
}
|
if (webhook.bodySchema) {
|
||||||
const target = await db.get(webhook.action.target)
|
validate(ctx.request.body, webhook.bodySchema)
|
||||||
if (webhook.action.type === exports.WebhookType.AUTOMATION) {
|
}
|
||||||
// trigger with both the pure request and then expand it
|
const target = await db.get(webhook.action.target)
|
||||||
// incase the user has produced a schema to bind to
|
if (webhook.action.type === exports.WebhookType.AUTOMATION) {
|
||||||
await triggers.externalTrigger(target, {
|
// trigger with both the pure request and then expand it
|
||||||
body: ctx.request.body,
|
// incase the user has produced a schema to bind to
|
||||||
...ctx.request.body,
|
await triggers.externalTrigger(target, {
|
||||||
appId: ctx.params.instance,
|
body: ctx.request.body,
|
||||||
})
|
...ctx.request.body,
|
||||||
}
|
appId: prodAppId,
|
||||||
ctx.status = 200
|
})
|
||||||
ctx.body = {
|
}
|
||||||
message: "Webhook trigger fired successfully",
|
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,6 +85,18 @@ exports.run = async function ({ inputs }) {
|
||||||
const request = {
|
const request = {
|
||||||
method: requestMethod,
|
method: requestMethod,
|
||||||
}
|
}
|
||||||
|
if (headers) {
|
||||||
|
try {
|
||||||
|
const customHeaders =
|
||||||
|
typeof headers === "string" ? JSON.parse(headers) : headers
|
||||||
|
request.headers = { ...request.headers, ...customHeaders }
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
response: "Unable to process headers, must be a JSON object.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
requestBody &&
|
requestBody &&
|
||||||
requestBody.length !== 0 &&
|
requestBody.length !== 0 &&
|
||||||
|
@ -95,21 +107,9 @@ exports.run = async function ({ inputs }) {
|
||||||
? requestBody
|
? requestBody
|
||||||
: JSON.stringify(requestBody)
|
: JSON.stringify(requestBody)
|
||||||
request.headers = {
|
request.headers = {
|
||||||
|
...request.headers,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headers) {
|
|
||||||
try {
|
|
||||||
const customHeaders =
|
|
||||||
typeof headers === "string" ? JSON.parse(headers) : headers
|
|
||||||
request.headers = { ...request.headers, ...customHeaders }
|
|
||||||
} catch (err) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
response: "Unable to process headers, must be a JSON object.",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -122,7 +122,7 @@ exports.run = async function ({ inputs }) {
|
||||||
return {
|
return {
|
||||||
httpStatus: status,
|
httpStatus: status,
|
||||||
response: message,
|
response: message,
|
||||||
success: status === 200,
|
success: status >= 200 && status <= 206,
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
|
|
|
@ -6,6 +6,7 @@ const { queue } = require("./bullboard")
|
||||||
const newid = require("../db/newid")
|
const newid = require("../db/newid")
|
||||||
const { updateEntityMetadata } = require("../utilities")
|
const { updateEntityMetadata } = require("../utilities")
|
||||||
const { MetadataTypes } = require("../constants")
|
const { MetadataTypes } = require("../constants")
|
||||||
|
const { getDeployedAppID } = require("@budibase/auth/db")
|
||||||
|
|
||||||
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
||||||
const CRON_STEP_ID = definitions.CRON.stepId
|
const CRON_STEP_ID = definitions.CRON.stepId
|
||||||
|
@ -150,9 +151,13 @@ exports.checkForWebhooks = async ({ appId, oldAuto, newAuto }) => {
|
||||||
await webhooks.save(ctx)
|
await webhooks.save(ctx)
|
||||||
const id = ctx.body.webhook._id
|
const id = ctx.body.webhook._id
|
||||||
newTrigger.webhookId = 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 = {
|
newTrigger.inputs = {
|
||||||
schemaUrl: `api/webhooks/schema/${appId}/${id}`,
|
schemaUrl: `api/webhooks/schema/${appId}/${id}`,
|
||||||
triggerUrl: `api/webhooks/trigger/${appId}/${id}`,
|
triggerUrl: `api/webhooks/trigger/${prodAppId}/${id}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newAuto
|
return newAuto
|
||||||
|
|
|
@ -142,13 +142,11 @@ module RestModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseResponse(response: any) {
|
async parseResponse(response: any) {
|
||||||
switch (this.headers.Accept) {
|
const contentType = response.headers.get("content-type")
|
||||||
case "application/json":
|
if (contentType && contentType.indexOf("application/json") !== -1) {
|
||||||
return await response.json()
|
return await response.json()
|
||||||
case "text/html":
|
} else {
|
||||||
return await response.text()
|
return await response.text()
|
||||||
default:
|
|
||||||
return await response.json()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +189,7 @@ module RestModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(this.getUrl(path, queryString), {
|
const response = await fetch(this.getUrl(path, queryString), {
|
||||||
method: "POST",
|
method: "PUT",
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: JSON.stringify(json),
|
body: JSON.stringify(json),
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
jest.mock("node-fetch", () =>
|
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 fetch = require("node-fetch")
|
||||||
const RestIntegration = require("../rest")
|
const RestIntegration = require("../rest")
|
||||||
|
|
|
@ -5,20 +5,17 @@ const {
|
||||||
doesHaveBasePermission,
|
doesHaveBasePermission,
|
||||||
} = require("@budibase/auth/permissions")
|
} = require("@budibase/auth/permissions")
|
||||||
const builderMiddleware = require("./builder")
|
const builderMiddleware = require("./builder")
|
||||||
|
const { isWebhookEndpoint } = require("./utils")
|
||||||
|
|
||||||
function hasResource(ctx) {
|
function hasResource(ctx) {
|
||||||
return ctx.resourceId != null
|
return ctx.resourceId != null
|
||||||
}
|
}
|
||||||
|
|
||||||
const WEBHOOK_ENDPOINTS = new RegExp(
|
|
||||||
["webhooks/trigger", "webhooks/schema"].join("|")
|
|
||||||
)
|
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
(permType, permLevel = null) =>
|
(permType, permLevel = null) =>
|
||||||
async (ctx, next) => {
|
async (ctx, next) => {
|
||||||
// webhooks don't need authentication, each webhook unique
|
// webhooks don't need authentication, each webhook unique
|
||||||
if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) {
|
if (isWebhookEndpoint(ctx)) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ const { isUserInAppTenant } = require("@budibase/auth/tenancy")
|
||||||
const { getCachedSelf } = require("../utilities/global")
|
const { getCachedSelf } = require("../utilities/global")
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
|
const { isWebhookEndpoint } = require("./utils")
|
||||||
|
|
||||||
module.exports = async (ctx, next) => {
|
module.exports = async (ctx, next) => {
|
||||||
// try to get the appID from the request
|
// try to get the appID from the request
|
||||||
|
@ -38,6 +39,7 @@ module.exports = async (ctx, next) => {
|
||||||
// deny access to application preview
|
// deny access to application preview
|
||||||
if (
|
if (
|
||||||
isDevAppID(requestAppId) &&
|
isDevAppID(requestAppId) &&
|
||||||
|
!isWebhookEndpoint(ctx) &&
|
||||||
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
|
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
|
||||||
) {
|
) {
|
||||||
clearCookie(ctx, Cookies.CurrentApp)
|
clearCookie(ctx, Cookies.CurrentApp)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
const WEBHOOK_ENDPOINTS = new RegExp(
|
||||||
|
["webhooks/trigger", "webhooks/schema"].join("|")
|
||||||
|
)
|
||||||
|
|
||||||
|
exports.isWebhookEndpoint = ctx => {
|
||||||
|
return WEBHOOK_ENDPOINTS.test(ctx.request.url)
|
||||||
|
}
|
Loading…
Reference in New Issue