From 8024b46eed0d2e7dfb2b72012cdee4277c49fe02 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 6 Oct 2022 11:39:14 +0100 Subject: [PATCH 001/273] update CSP to account for another s3 URL --- hosting/nginx.prod.conf.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/nginx.prod.conf.hbs b/hosting/nginx.prod.conf.hbs index f3202ad4a4..d57a822f3f 100644 --- a/hosting/nginx.prod.conf.hbs +++ b/hosting/nginx.prod.conf.hbs @@ -55,7 +55,7 @@ http { set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; set $csp_object "object-src 'none'"; set $csp_base_uri "base-uri 'self'"; - set $csp_connect "connect-src 'self' https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.amazonaws.com https://*.s3.us-east-2.amazonaws.com https://*.s3.us-east-1.amazonaws.com https://*.s3.us-west-1.amazonaws.com https://*.s3.us-west-2.amazonaws.com https://*.s3.af-south-1.amazonaws.com https://*.s3.ap-east-1.amazonaws.com https://*.s3.ap-southeast-3.amazonaws.com https://*.s3.ap-south-1.amazonaws.com https://*.s3.ap-northeast-3.amazonaws.com https://*.s3.ap-northeast-2.amazonaws.com https://*.s3.ap-southeast-1.amazonaws.com https://*.s3.ap-southeast-2.amazonaws.com https://*.s3.ap-northeast-1.amazonaws.com https://*.s3.ca-central-1.amazonaws.com https://*.s3.cn-north-1.amazonaws.com https://*.s3.cn-northwest-1.amazonaws.com https://*.s3.eu-central-1.amazonaws.com https://*.s3.eu-west-1.amazonaws.com https://*.s3.eu-west-2.amazonaws.com https://*.s3.eu-south-1.amazonaws.com https://*.s3.eu-west-3.amazonaws.com https://*.s3.eu-north-1.amazonaws.com https://*.s3.sa-east-1.amazonaws.com https://*.s3.me-south-1.amazonaws.com https://*.s3.us-gov-east-1.amazonaws.com https://*.s3.us-gov-west-1.amazonaws.com"; + set $csp_connect "connect-src 'self' https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.amazonaws.com https://*.s3.us-east-2.amazonaws.com https://*.s3.us-east-1.amazonaws.com https://*.s3.us-west-1.amazonaws.com https://*.s3.us-west-2.amazonaws.com https://*.s3.af-south-1.amazonaws.com https://*.s3.ap-east-1.amazonaws.com https://*.s3.ap-southeast-3.amazonaws.com https://*.s3.ap-south-1.amazonaws.com https://*.s3.ap-northeast-3.amazonaws.com https://*.s3.ap-northeast-2.amazonaws.com https://*.s3.ap-southeast-1.amazonaws.com https://*.s3.ap-southeast-2.amazonaws.com https://*.s3.ap-northeast-1.amazonaws.com https://*.s3.ca-central-1.amazonaws.com https://*.s3.cn-north-1.amazonaws.com https://*.s3.cn-northwest-1.amazonaws.com https://*.s3.eu-central-1.amazonaws.com https://*.s3.eu-west-1.amazonaws.com https://*.s3.eu-west-2.amazonaws.com https://*.s3.eu-south-1.amazonaws.com https://*.s3.eu-west-3.amazonaws.com https://*.s3.eu-north-1.amazonaws.com https://*.s3.sa-east-1.amazonaws.com https://s3.sa-east-1.amazonaws.com https://*.s3.me-south-1.amazonaws.com https://*.s3.us-gov-east-1.amazonaws.com https://*.s3.us-gov-west-1.amazonaws.com"; set $csp_font "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com https://js.intercomcdn.com https://fonts.intercomcdn.com"; set $csp_frame "frame-src 'self' https:"; set $csp_img "img-src http: https: data: blob:"; From 73c99910b11536395eea8ec8ffbdc665b163d53c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 7 Feb 2023 15:32:59 +0000 Subject: [PATCH 002/273] initial commit of API design session outcomes. --- .../types/src/api/web/global/auditLogs.ts | 36 +++++++++++++++++++ packages/types/src/api/web/global/index.ts | 1 + packages/types/src/api/web/index.ts | 1 + packages/types/src/api/web/pagination.ts | 24 +++++++++++++ .../types/src/documents/global/auditLogs.ts | 11 ++++++ packages/types/src/sdk/events/event.ts | 4 +++ 6 files changed, 77 insertions(+) create mode 100644 packages/types/src/api/web/global/auditLogs.ts create mode 100644 packages/types/src/api/web/pagination.ts create mode 100644 packages/types/src/documents/global/auditLogs.ts diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts new file mode 100644 index 0000000000..7281d0ca36 --- /dev/null +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -0,0 +1,36 @@ +import { Event, AuditedEventFriendlyName } from "../../../sdk" +import { PaginationResponse, PaginationRequest } from "../" + +export interface DownloadAuditLogsRequest { + userId?: string[] + appId?: string[] + event?: Event[] + startDate?: string + endDate?: string + metadataSearch?: string +} + +export interface SearchAuditLogsRequest + extends PaginationRequest, + DownloadAuditLogsRequest {} + +export interface SearchAuditLogsResponse extends PaginationResponse { + data: { + app: { + _id: string + name: string + } + user: { + _id: string + name: string + } + event: Event + timestamp: string + name: string + metadata: any + }[] +} + +export interface DefinitionsAuditLogsResponse { + events: typeof AuditedEventFriendlyName +} diff --git a/packages/types/src/api/web/global/index.ts b/packages/types/src/api/web/global/index.ts index 415ed55ab1..f9eec2a779 100644 --- a/packages/types/src/api/web/global/index.ts +++ b/packages/types/src/api/web/global/index.ts @@ -1,2 +1,3 @@ export * from "./environmentVariables" +export * from "./auditLogs" export * from "./events" diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index 9688a89c7b..3d209f22bb 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -4,3 +4,4 @@ export * from "./errors" export * from "./schedule" export * from "./app" export * from "./global" +export * from "./pagination" diff --git a/packages/types/src/api/web/pagination.ts b/packages/types/src/api/web/pagination.ts new file mode 100644 index 0000000000..ca640d58db --- /dev/null +++ b/packages/types/src/api/web/pagination.ts @@ -0,0 +1,24 @@ +export enum SortOrder { + ASCENDING = "ascending", + DESCENDING = "descending", +} + +export enum SortType { + STRING = "string", + number = "number", +} + +export interface PaginationRequest { + limit?: number + bookmark?: string + sort?: { + order: SortOrder + column: string + type: SortType + } +} + +export interface PaginationResponse { + bookmark: string + hasNextPage: boolean +} diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts new file mode 100644 index 0000000000..bc07bc88d4 --- /dev/null +++ b/packages/types/src/documents/global/auditLogs.ts @@ -0,0 +1,11 @@ +import { Document } from "../document" +import { Event } from "../../sdk" + +export interface AuditLogDocument extends Document { + appId: string + event: Event + userId: string + timestamp: string + metadata: any + name: string +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index f509682add..614dd18ded 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -182,6 +182,10 @@ export enum Event { ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", } +export const AuditedEventFriendlyName = { + [Event.USER_CREATED]: "user created", +} + // properties added at the final stage of the event pipeline export interface BaseEvent { version?: string From 26becc9950ffdc4ed0965147654280bdd47c6fe0 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 8 Feb 2023 15:18:44 +0000 Subject: [PATCH 003/273] add generic page for paywall features --- .../portal/_components/LockedFeature.svelte | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte diff --git a/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte b/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte new file mode 100644 index 0000000000..e6f4075e2e --- /dev/null +++ b/packages/builder/src/pages/builder/portal/_components/LockedFeature.svelte @@ -0,0 +1,76 @@ + + + + +
+ {title} + {#if !enabled} + + {planType} + + {/if} +
+ {description} +
+ + + {#if enabled} + + {:else} +
+ + + +
+ {/if} +
+ + From 2bd6ff627a83db7cd0984e20b3aec654c8022b94 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 10 Feb 2023 14:57:42 +0000 Subject: [PATCH 004/273] update env vars with geneic splash screen --- .../portal/settings/environment/index.svelte | 120 +++++------------- 1 file changed, 34 insertions(+), 86 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte index 3c170235e9..cff578febd 100644 --- a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte @@ -1,21 +1,17 @@ - - -
- Environment Variables - {#if !$licensing.environmentVariablesEnabled} - - Business plan - - {/if} -
- Add and manage environment variables for development and production -
- - - {#if $licensing.environmentVariablesEnabled} - {#if noEncryptionKey} - - {/if} -
- -
- - - - - {:else} -
- - - -
+ { + await environment.upgradePanelOpened() + $licensing.goToUpgradePage() + }} +> + {#if noEncryptionKey} + {/if} - +
+ +
+ +
+ + From 70ac7b81c3921b77cddce72d95816d2ada6fde94 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 09:47:08 +0000 Subject: [PATCH 005/273] add base audit logs ui --- .../bbui/src/Form/Core/Multiselect.svelte | 2 + packages/bbui/src/Form/Core/Picker.svelte | 11 +- packages/bbui/src/Form/Multiselect.svelte | 5 + packages/bbui/src/Form/Select.svelte | 2 + .../builder/portal/account/_layout.svelte | 3 +- .../auditLogs/_components/UserRenderer.svelte | 6 + .../_components/ViewDetailsRenderer.svelte | 13 ++ .../portal/account/auditLogs/index.svelte | 200 ++++++++++++++++++ .../overview/[appId]/backups/index.svelte | 2 +- .../portal/settings/environment/index.svelte | 1 + .../builder/src/stores/portal/licensing.js | 5 + packages/builder/src/stores/portal/menu.js | 5 + packages/frontend-core/src/constants.js | 1 + 13 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index d6c4dc23ac..a315f44a65 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -14,6 +14,7 @@ export let autocomplete = false export let sort = false export let autoWidth = false + export let fetchTerm = null const dispatch = createEventDispatcher() @@ -83,6 +84,7 @@ {options} isPlaceholder={!value?.length} {autocomplete} + bind:fetchTerm {isOptionSelected} {getOptionLabel} {getOptionValue} diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 32cfcf3310..acd3c5da61 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -31,7 +31,8 @@ export let autoWidth = false export let autocomplete = false export let sort = false - + export let fetchTerm = null + $: console.log(fieldText) const dispatch = createEventDispatcher() let searchTerm = null @@ -71,7 +72,7 @@ } const getFilteredOptions = (options, term, getLabel) => { - if (autocomplete && term) { + if (autocomplete && term && !fetchTerm) { const lowerCaseTerm = term.toLowerCase() return options.filter(option => { return `${getLabel(option)}`.toLowerCase().includes(lowerCaseTerm) @@ -144,8 +145,8 @@ > {#if autocomplete} (searchTerm = event.detail)} + value={fetchTerm ? fetchTerm : searchTerm} + on:change={event => (fetchTerm = event.detail)} {disabled} placeholder="Search" /> @@ -247,7 +248,7 @@ } .popover-content.auto-width .spectrum-Menu-itemLabel { white-space: nowrap; - overflow: hidden; + overflow: none; text-overflow: ellipsis; } .popover-content:not(.auto-width) .spectrum-Menu-itemLabel { diff --git a/packages/bbui/src/Form/Multiselect.svelte b/packages/bbui/src/Form/Multiselect.svelte index 7bcf22aa06..d28401b608 100644 --- a/packages/bbui/src/Form/Multiselect.svelte +++ b/packages/bbui/src/Form/Multiselect.svelte @@ -15,6 +15,9 @@ export let getOptionValue = option => option export let sort = false export let autoWidth = false + export let autocomplete = false + export let fetchTerm = null + const dispatch = createEventDispatcher() const onChange = e => { value = e.detail @@ -34,6 +37,8 @@ {getOptionLabel} {getOptionValue} {autoWidth} + {autocomplete} + bind:fetchTerm on:change={onChange} on:click /> diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 69126e648d..4f30318282 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -20,6 +20,7 @@ export let autoWidth = false export let sort = false export let tooltip = "" + export let autocomplete = false const dispatch = createEventDispatcher() const onChange = e => { @@ -51,6 +52,7 @@ {getOptionIcon} {getOptionColour} {isOptionEnabled} + {autocomplete} on:change={onChange} on:click /> diff --git a/packages/builder/src/pages/builder/portal/account/_layout.svelte b/packages/builder/src/pages/builder/portal/account/_layout.svelte index 3083b574a8..892e853aad 100644 --- a/packages/builder/src/pages/builder/portal/account/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/account/_layout.svelte @@ -4,12 +4,13 @@ import { Content, SideNav, SideNavItem } from "components/portal/page" import { menu } from "stores/portal" + $: wide = $isActive("./auditLogs") $: pages = $menu.find(x => x.title === "Account")?.subPages || [] $: !pages.length && $goto("../") - +
{#each pages as { title, href }} diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte new file mode 100644 index 0000000000..4baa24403e --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte new file mode 100644 index 0000000000..a222871966 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte @@ -0,0 +1,13 @@ + + +Edit diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte new file mode 100644 index 0000000000..a5d403491a --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -0,0 +1,200 @@ + + + { + $licensing.goToUpgradePage() + }} +> +
+
+ + + +{#if selectedLog} + +
hello
+
+{/if} + + diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte index c15f944601..49b4a5babc 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/index.svelte @@ -184,7 +184,7 @@ {#if !$licensing.backupsEnabled} - {#if !$auth.accountPortalAccess && !$licensing.groupsEnabled && $admin.cloud} + {#if !$auth.accountPortalAccess && $admin.cloud} Contact your account holder to upgrade your plan. {/if}
diff --git a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte index cff578febd..013d6b8ff4 100644 --- a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte @@ -55,6 +55,7 @@ notifications.error(`Error saving variable: ${err.message}`) } } + $: console.log($environment.variables) { Constants.Features.ENVIRONMENT_VARIABLES ) + let auditLogsEnabled = license.features.includes( + Constants.Features.AUDIT_LOGS + ) + auditLogsEnabled = true store.update(state => { return { ...state, @@ -72,6 +76,7 @@ export const createLicensingStore = () => { groupsEnabled, backupsEnabled, environmentVariablesEnabled, + auditLogsEnabled, } }) }, diff --git a/packages/builder/src/stores/portal/menu.js b/packages/builder/src/stores/portal/menu.js index 8eea36c08c..56956fc330 100644 --- a/packages/builder/src/stores/portal/menu.js +++ b/packages/builder/src/stores/portal/menu.js @@ -75,6 +75,10 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => { title: "Usage", href: "/builder/portal/account/usage", }, + { + title: "Audit Logs", + href: "/builder/portal/account/auditLogs", + }, ] if ($admin.cloud && $auth?.user?.accountPortalAccess) { accountSubPages.push({ @@ -87,6 +91,7 @@ export const menu = derived([admin, auth], ([$admin, $auth]) => { href: "/builder/portal/account/upgrade", }) } + // add license check here if ( $auth?.user?.accountPortalAccess && $auth.user.account.stripeCustomerId diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index 3a16013df2..8c7103a88f 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -115,6 +115,7 @@ export const Features = { USER_GROUPS: "userGroups", BACKUPS: "appBackups", ENVIRONMENT_VARIABLES: "environmentVariables", + AUDIT_LOGS: "auditLogs", } // Role IDs From 2d2c960b75775feea171e09950327143a64838d5 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 11:43:25 +0000 Subject: [PATCH 006/273] add audit logs feature --- packages/builder/src/stores/portal/licensing.js | 3 +-- packages/types/src/sdk/licensing/feature.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index 9adb76fa8c..4215e92741 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -64,10 +64,9 @@ export const createLicensingStore = () => { Constants.Features.ENVIRONMENT_VARIABLES ) - let auditLogsEnabled = license.features.includes( + const auditLogsEnabled = license.features.includes( Constants.Features.AUDIT_LOGS ) - auditLogsEnabled = true store.update(state => { return { ...state, diff --git a/packages/types/src/sdk/licensing/feature.ts b/packages/types/src/sdk/licensing/feature.ts index a39bcab18b..7ebd1574ca 100644 --- a/packages/types/src/sdk/licensing/feature.ts +++ b/packages/types/src/sdk/licensing/feature.ts @@ -2,4 +2,5 @@ export enum Feature { USER_GROUPS = "userGroups", APP_BACKUPS = "appBackups", ENVIRONMENT_VARIABLES = "environmentVariables", + AUDIT_LOGS = "auditLogs", } From 5cd6cb166ab51f0d07bab1367d0549abd8aaa6af Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 13 Feb 2023 11:53:01 +0000 Subject: [PATCH 007/273] Configurable test log levels and common error handling --- .../src/middleware/errorHandling.ts | 28 +++++++++++++++ packages/backend-core/src/middleware/index.ts | 5 +-- packages/backend-core/tests/jestEnv.ts | 28 +++------------ packages/backend-core/tests/jestSetup.ts | 21 +++++++++++- packages/backend-core/tests/logging.ts | 34 +++++++++++++++++++ packages/server/src/api/index.ts | 25 ++------------ packages/server/src/tests/jestEnv.ts | 12 +++---- packages/server/src/tests/jestSetup.ts | 1 + packages/server/src/tests/logging.ts | 34 +++++++++++++++++++ packages/types/src/api/web/errors.ts | 1 + packages/worker/src/api/index.ts | 24 +++---------- .../routes/system/tests/migrations.spec.ts | 4 +-- .../src/middleware/tests/tenancy.spec.ts | 8 ++--- packages/worker/src/tests/jestEnv.ts | 2 +- packages/worker/src/tests/jestSetup.ts | 7 ++-- packages/worker/src/tests/logging.ts | 34 +++++++++++++++++++ 16 files changed, 182 insertions(+), 86 deletions(-) create mode 100644 packages/backend-core/src/middleware/errorHandling.ts create mode 100644 packages/backend-core/tests/logging.ts create mode 100644 packages/server/src/tests/logging.ts create mode 100644 packages/worker/src/tests/logging.ts diff --git a/packages/backend-core/src/middleware/errorHandling.ts b/packages/backend-core/src/middleware/errorHandling.ts new file mode 100644 index 0000000000..1baaa92501 --- /dev/null +++ b/packages/backend-core/src/middleware/errorHandling.ts @@ -0,0 +1,28 @@ +import { APIError } from "@budibase/types" +import * as errors from "../errors" +import env from "../environment" + +export async function errorHandling(ctx: any, next: any) { + try { + await next() + } catch (err: any) { + const status = err.status || err.statusCode || 500 + ctx.status = status + + if (status > 499 || env.LOG_4XX) { + ctx.log.error(err) + } + + const error = errors.getPublicError(err) + const body: APIError = { + message: err.message, + status: status, + validationErrors: err.validation, + error, + } + + ctx.body = body + } +} + +export default errorHandling diff --git a/packages/backend-core/src/middleware/index.ts b/packages/backend-core/src/middleware/index.ts index 4986cde64b..de609f9a3e 100644 --- a/packages/backend-core/src/middleware/index.ts +++ b/packages/backend-core/src/middleware/index.ts @@ -1,7 +1,7 @@ export * as jwt from "./passport/jwt" export * as local from "./passport/local" -export * as google from "./passport/google" -export * as oidc from "./passport/oidc" +export * as google from "./passport/sso/google" +export * as oidc from "./passport/sso/oidc" import * as datasourceGoogle from "./passport/datasource/google" export const datasource = { google: datasourceGoogle, @@ -16,4 +16,5 @@ export { default as adminOnly } from "./adminOnly" export { default as builderOrAdmin } from "./builderOrAdmin" export { default as builderOnly } from "./builderOnly" export { default as logging } from "./logging" +export { default as errorHandling } from "./errorHandling" export * as joiValidator from "./joi-validator" diff --git a/packages/backend-core/tests/jestEnv.ts b/packages/backend-core/tests/jestEnv.ts index 1190eb3bb7..71cf865737 100644 --- a/packages/backend-core/tests/jestEnv.ts +++ b/packages/backend-core/tests/jestEnv.ts @@ -1,23 +1,5 @@ -import env from "../src/environment" -import { mocks } from "./utilities" - -// must explicitly enable fetch mock -mocks.fetch.enable() - -// mock all dates to 2020-01-01T00:00:00.000Z -// use tk.reset() to use real dates in individual tests -import tk from "timekeeper" -tk.freeze(mocks.date.MOCK_DATE) - -env._set("SELF_HOSTED", "1") -env._set("NODE_ENV", "jest") - -if (!process.env.DEBUG) { - global.console.log = jest.fn() // console.log are ignored in tests -} - -if (!process.env.CI) { - // set a longer timeout in dev for debugging - // 100 seconds - jest.setTimeout(100000) -} +process.env.SELF_HOSTED = "1" +process.env.MULTI_TENANCY = "1" +process.env.NODE_ENV = "jest" +process.env.MOCK_REDIS = "1" +process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" diff --git a/packages/backend-core/tests/jestSetup.ts b/packages/backend-core/tests/jestSetup.ts index f7887ec824..e786086de6 100644 --- a/packages/backend-core/tests/jestSetup.ts +++ b/packages/backend-core/tests/jestSetup.ts @@ -1,4 +1,23 @@ +import "./logging" import env from "../src/environment" -import { testContainerUtils } from "./utilities" +import { mocks, testContainerUtils } from "./utilities" + +// must explicitly enable fetch mock +mocks.fetch.enable() + +// mock all dates to 2020-01-01T00:00:00.000Z +// use tk.reset() to use real dates in individual tests +import tk from "timekeeper" +tk.freeze(mocks.date.MOCK_DATE) + +if (!process.env.DEBUG) { + console.log = jest.fn() // console.log are ignored in tests +} + +if (!process.env.CI) { + // set a longer timeout in dev for debugging + // 100 seconds + jest.setTimeout(100000) +} testContainerUtils.setupEnv(env) diff --git a/packages/backend-core/tests/logging.ts b/packages/backend-core/tests/logging.ts new file mode 100644 index 0000000000..271f4d62ff --- /dev/null +++ b/packages/backend-core/tests/logging.ts @@ -0,0 +1,34 @@ +export enum LogLevel { + TRACE = "trace", + DEBUG = "debug", + INFO = "info", + WARN = "warn", + ERROR = "error", +} + +const LOG_INDEX: { [key in LogLevel]: number } = { + [LogLevel.TRACE]: 1, + [LogLevel.DEBUG]: 2, + [LogLevel.INFO]: 3, + [LogLevel.WARN]: 4, + [LogLevel.ERROR]: 5, +} + +const setIndex = LOG_INDEX[process.env.LOG_LEVEL as LogLevel] + +if (setIndex > LOG_INDEX.trace) { + global.console.trace = jest.fn() +} + +if (setIndex > LOG_INDEX.debug) { + global.console.debug = jest.fn() +} + +if (setIndex > LOG_INDEX.info) { + global.console.info = jest.fn() + global.console.log = jest.fn() +} + +if (setIndex > LOG_INDEX.warn) { + global.console.warn = jest.fn() +} diff --git a/packages/server/src/api/index.ts b/packages/server/src/api/index.ts index 3375161dd8..78a6056366 100644 --- a/packages/server/src/api/index.ts +++ b/packages/server/src/api/index.ts @@ -1,5 +1,5 @@ import Router from "@koa/router" -import { errors, auth } from "@budibase/backend-core" +import { auth, middleware } from "@budibase/backend-core" import currentApp from "../middleware/currentapp" import zlib from "zlib" import { mainRoutes, staticRoutes, publicRoutes } from "./routes" @@ -14,6 +14,8 @@ export const router: Router = new Router() router.get("/health", ctx => (ctx.status = 200)) router.get("/version", ctx => (ctx.body = pkg.version)) +router.use(middleware.errorHandling) + router .use( compress({ @@ -54,27 +56,6 @@ router .use(currentApp) .use(auth.auditLog) -// error handling middleware -router.use(async (ctx, next) => { - try { - await next() - } catch (err: any) { - ctx.status = err.status || err.statusCode || 500 - const error = errors.getPublicError(err) - ctx.body = { - message: err.message, - status: ctx.status, - validationErrors: err.validation, - error, - } - ctx.log.error(err) - // unauthorised errors don't provide a useful trace - if (!env.isTest()) { - console.trace(err) - } - } -}) - // authenticated routes for (let route of mainRoutes) { router.use(route.routes()) diff --git a/packages/server/src/tests/jestEnv.ts b/packages/server/src/tests/jestEnv.ts index 9707893bd9..b1ef038c1b 100644 --- a/packages/server/src/tests/jestEnv.ts +++ b/packages/server/src/tests/jestEnv.ts @@ -1,9 +1,9 @@ -import env from "../environment" import { tmpdir } from "os" -env._set("SELF_HOSTED", "1") -env._set("NODE_ENV", "jest") -env._set("MULTI_TENANCY", "1") +process.env.SELF_HOSTED = "1" +process.env.NODE_ENV = "jest" +process.env.MULTI_TENANCY = "1" // @ts-ignore -env._set("BUDIBASE_DIR", tmpdir("budibase-unittests")) -env._set("LOG_LEVEL", "silent") +process.env.BUDIBASE_DIR = tmpdir("budibase-unittests") +process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" +process.env.MOCK_REDIS = "1" diff --git a/packages/server/src/tests/jestSetup.ts b/packages/server/src/tests/jestSetup.ts index d87ccbfe7c..b052d9941b 100644 --- a/packages/server/src/tests/jestSetup.ts +++ b/packages/server/src/tests/jestSetup.ts @@ -1,3 +1,4 @@ +import "./logging" import env from "../environment" import { env as coreEnv } from "@budibase/backend-core" import { testContainerUtils } from "@budibase/backend-core/tests" diff --git a/packages/server/src/tests/logging.ts b/packages/server/src/tests/logging.ts new file mode 100644 index 0000000000..271f4d62ff --- /dev/null +++ b/packages/server/src/tests/logging.ts @@ -0,0 +1,34 @@ +export enum LogLevel { + TRACE = "trace", + DEBUG = "debug", + INFO = "info", + WARN = "warn", + ERROR = "error", +} + +const LOG_INDEX: { [key in LogLevel]: number } = { + [LogLevel.TRACE]: 1, + [LogLevel.DEBUG]: 2, + [LogLevel.INFO]: 3, + [LogLevel.WARN]: 4, + [LogLevel.ERROR]: 5, +} + +const setIndex = LOG_INDEX[process.env.LOG_LEVEL as LogLevel] + +if (setIndex > LOG_INDEX.trace) { + global.console.trace = jest.fn() +} + +if (setIndex > LOG_INDEX.debug) { + global.console.debug = jest.fn() +} + +if (setIndex > LOG_INDEX.info) { + global.console.info = jest.fn() + global.console.log = jest.fn() +} + +if (setIndex > LOG_INDEX.warn) { + global.console.warn = jest.fn() +} diff --git a/packages/types/src/api/web/errors.ts b/packages/types/src/api/web/errors.ts index 65870d6a29..996c0ba34c 100644 --- a/packages/types/src/api/web/errors.ts +++ b/packages/types/src/api/web/errors.ts @@ -2,4 +2,5 @@ export interface APIError { message: string status: number error?: any + validationErrors?: any } diff --git a/packages/worker/src/api/index.ts b/packages/worker/src/api/index.ts index d8df62f532..b390d36bb8 100644 --- a/packages/worker/src/api/index.ts +++ b/packages/worker/src/api/index.ts @@ -3,8 +3,7 @@ const compress = require("koa-compress") const zlib = require("zlib") import { routes } from "./routes" import { middleware as pro } from "@budibase/pro" -import { errors, auth, middleware } from "@budibase/backend-core" -import { APIError } from "@budibase/types" +import { auth, middleware } from "@budibase/backend-core" const PUBLIC_ENDPOINTS = [ // deprecated single tenant sso callback @@ -109,7 +108,9 @@ const NO_TENANCY_ENDPOINTS = [ const NO_CSRF_ENDPOINTS = [...PUBLIC_ENDPOINTS] const router: Router = new Router() + router + .use(middleware.errorHandling) .use( compress({ threshold: 2048, @@ -136,29 +137,12 @@ router (!ctx.isAuthenticated || (ctx.user && !ctx.user.budibaseAccess)) && !ctx.internal ) { - ctx.throw(403, "Unauthorized - no public worker access") + ctx.throw(403, "Unauthorized") } return next() }) .use(middleware.auditLog) -// error handling middleware - TODO: This could be moved to backend-core -router.use(async (ctx, next) => { - try { - await next() - } catch (err: any) { - ctx.log.error(err) - ctx.status = err.status || err.statusCode || 500 - const error = errors.getPublicError(err) - const body: APIError = { - message: err.message, - status: ctx.status, - error, - } - ctx.body = body - } -}) - router.get("/health", ctx => (ctx.status = 200)) // authenticated routes diff --git a/packages/worker/src/api/routes/system/tests/migrations.spec.ts b/packages/worker/src/api/routes/system/tests/migrations.spec.ts index 304a64761e..950f5c2153 100644 --- a/packages/worker/src/api/routes/system/tests/migrations.spec.ts +++ b/packages/worker/src/api/routes/system/tests/migrations.spec.ts @@ -30,7 +30,7 @@ describe("/api/system/migrations", () => { headers: {}, status: 403, }) - expect(res.text).toBe("Unauthorized - no public worker access") + expect(res.body).toEqual({ message: "Unauthorized", status: 403 }) expect(migrateFn).toBeCalledTimes(0) }) @@ -47,7 +47,7 @@ describe("/api/system/migrations", () => { headers: {}, status: 403, }) - expect(res.text).toBe("Unauthorized - no public worker access") + expect(res.body).toEqual({ message: "Unauthorized", status: 403 }) }) it("returns definitions", async () => { diff --git a/packages/worker/src/middleware/tests/tenancy.spec.ts b/packages/worker/src/middleware/tests/tenancy.spec.ts index a8b7a50e55..8853291634 100644 --- a/packages/worker/src/middleware/tests/tenancy.spec.ts +++ b/packages/worker/src/middleware/tests/tenancy.spec.ts @@ -24,7 +24,7 @@ describe("tenancy middleware", () => { }) it("should get tenant id from header", async () => { - const tenantId = structures.uuid() + const tenantId = structures.tenant.id() const headers = { [constants.Header.TENANT_ID]: tenantId, } @@ -35,7 +35,7 @@ describe("tenancy middleware", () => { }) it("should get tenant id from query param", async () => { - const tenantId = structures.uuid() + const tenantId = structures.tenant.id() const res = await config.request.get( `/api/global/configs/checklist?tenantId=${tenantId}` ) @@ -43,7 +43,7 @@ describe("tenancy middleware", () => { }) it("should get tenant id from subdomain", async () => { - const tenantId = structures.uuid() + const tenantId = structures.tenant.id() const headers = { host: `${tenantId}.localhost:10000`, } @@ -67,7 +67,7 @@ describe("tenancy middleware", () => { it("should throw when no tenant id is found", async () => { const res = await config.request.get(`/api/global/configs/checklist`) expect(res.status).toBe(403) - expect(res.text).toBe("Tenant id not set") + expect(res.body).toEqual({ message: "Tenant id not set", status: 403 }) expect(res.headers[constants.Header.TENANT_ID]).toBe(undefined) }) }) diff --git a/packages/worker/src/tests/jestEnv.ts b/packages/worker/src/tests/jestEnv.ts index 0b27cf52aa..602a505c1b 100644 --- a/packages/worker/src/tests/jestEnv.ts +++ b/packages/worker/src/tests/jestEnv.ts @@ -1,7 +1,7 @@ process.env.SELF_HOSTED = "0" process.env.NODE_ENV = "jest" process.env.JWT_SECRET = "test-jwtsecret" -process.env.LOG_LEVEL = "silent" +process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" process.env.MULTI_TENANCY = "1" process.env.MINIO_URL = "http://localhost" process.env.MINIO_ACCESS_KEY = "test" diff --git a/packages/worker/src/tests/jestSetup.ts b/packages/worker/src/tests/jestSetup.ts index 2deef96176..31d36f00ae 100644 --- a/packages/worker/src/tests/jestSetup.ts +++ b/packages/worker/src/tests/jestSetup.ts @@ -1,5 +1,6 @@ -import { mocks, testContainerUtils } from "@budibase/backend-core/tests" +import "./logging" +import { mocks, testContainerUtils } from "@budibase/backend-core/tests" import env from "../environment" import { env as coreEnv } from "@budibase/backend-core" @@ -11,10 +12,6 @@ mocks.fetch.enable() const tk = require("timekeeper") tk.freeze(mocks.date.MOCK_DATE) -if (!process.env.DEBUG) { - global.console.log = jest.fn() // console.log are ignored in tests -} - if (!process.env.CI) { // set a longer timeout in dev for debugging // 100 seconds diff --git a/packages/worker/src/tests/logging.ts b/packages/worker/src/tests/logging.ts new file mode 100644 index 0000000000..271f4d62ff --- /dev/null +++ b/packages/worker/src/tests/logging.ts @@ -0,0 +1,34 @@ +export enum LogLevel { + TRACE = "trace", + DEBUG = "debug", + INFO = "info", + WARN = "warn", + ERROR = "error", +} + +const LOG_INDEX: { [key in LogLevel]: number } = { + [LogLevel.TRACE]: 1, + [LogLevel.DEBUG]: 2, + [LogLevel.INFO]: 3, + [LogLevel.WARN]: 4, + [LogLevel.ERROR]: 5, +} + +const setIndex = LOG_INDEX[process.env.LOG_LEVEL as LogLevel] + +if (setIndex > LOG_INDEX.trace) { + global.console.trace = jest.fn() +} + +if (setIndex > LOG_INDEX.debug) { + global.console.debug = jest.fn() +} + +if (setIndex > LOG_INDEX.info) { + global.console.info = jest.fn() + global.console.log = jest.fn() +} + +if (setIndex > LOG_INDEX.warn) { + global.console.warn = jest.fn() +} From ae9979929ad92b8be257422e8cd6c6339892e8c4 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 13 Feb 2023 11:57:30 +0000 Subject: [PATCH 008/273] Enable higher concurrency and resiliency in worker tests --- packages/backend-core/package.json | 4 +- .../src/cache/tests/writethrough.spec.js | 61 ------ .../src/cache/tests/writethrough.spec.ts | 73 +++++++ packages/backend-core/src/cache/user.ts | 14 +- .../backend-core/src/context/deprovision.ts | 108 ---------- .../src/context/tests/index.spec.ts | 11 +- packages/backend-core/src/db/db.ts | 3 +- .../src/db/tests/utils.seq.spec.ts | 190 ----------------- .../backend-core/src/db/tests/utils.spec.ts | 192 +++++++++++++++++ packages/backend-core/src/db/views.ts | 64 +++--- packages/backend-core/src/events/analytics.ts | 4 +- .../posthog/tests/PosthogProcessor.spec.ts | 6 +- .../backend-core/src/featureFlags/index.ts | 4 +- packages/backend-core/src/index.ts | 20 +- .../src/middleware/authenticated.ts | 2 +- .../src/middleware/passport/utils.ts | 4 +- .../backend-core/src/middleware/tenancy.ts | 3 +- .../backend-core/src/migrations/migrations.ts | 8 +- .../src/objectStore/buckets/global.ts | 4 +- .../src/objectStore/buckets/plugins.ts | 4 +- packages/backend-core/src/platform/index.ts | 3 + .../backend-core/src/platform/platformDb.ts | 6 + packages/backend-core/src/platform/tenants.ts | 101 +++++++++ .../src/platform/tests/tenants.spec.ts | 25 +++ packages/backend-core/src/platform/users.ts | 90 ++++++++ packages/backend-core/src/redis/index.ts | 2 +- packages/backend-core/src/redis/redlock.ts | 39 ++-- packages/backend-core/src/tenancy/db.ts | 6 + packages/backend-core/src/tenancy/index.ts | 2 +- packages/backend-core/src/tenancy/tenancy.ts | 102 +-------- .../src/utils/tests/utils.spec.ts | 46 ++-- .../tests/utilities/DBTestConfiguration.ts | 32 +++ packages/backend-core/tests/utilities/db.ts | 9 - .../backend-core/tests/utilities/index.ts | 3 +- .../backend-core/tests/utilities/testEnv.ts | 16 +- packages/backend-core/yarn.lock | 8 +- packages/server/package.json | 3 +- .../src/api/routes/tests/backup.spec.ts | 1 - .../src/tests/utilities/TestConfiguration.ts | 96 +++++---- packages/server/yarn.lock | 109 ++++++---- packages/types/src/sdk/locks.ts | 1 + packages/worker/package.json | 5 +- .../src/api/controllers/global/users.ts | 49 +++-- .../src/api/controllers/system/tenants.ts | 12 +- .../api/routes/global/tests/configs.spec.ts | 198 ++++++++---------- .../src/api/routes/global/tests/roles.spec.ts | 5 +- .../src/api/routes/global/tests/users.spec.ts | 84 ++++---- .../worker/src/api/routes/system/tenants.ts | 2 +- .../api/routes/system/tests/restore.spec.ts | 4 +- .../api/routes/system/tests/status.spec.ts | 10 +- .../functions/globalInfoSyncUsers.ts | 7 +- packages/worker/src/sdk/tenants/index.ts | 1 + packages/worker/src/sdk/tenants/tenants.ts | 76 +++++++ packages/worker/src/sdk/users/users.ts | 2 +- .../worker/src/tests/TestConfiguration.ts | 121 ++++------- packages/worker/src/tests/api/base.ts | 3 +- packages/worker/src/tests/api/restore.ts | 1 + packages/worker/yarn.lock | 110 +++++----- 58 files changed, 1165 insertions(+), 1004 deletions(-) delete mode 100644 packages/backend-core/src/cache/tests/writethrough.spec.js create mode 100644 packages/backend-core/src/cache/tests/writethrough.spec.ts delete mode 100644 packages/backend-core/src/context/deprovision.ts delete mode 100644 packages/backend-core/src/db/tests/utils.seq.spec.ts create mode 100644 packages/backend-core/src/db/tests/utils.spec.ts create mode 100644 packages/backend-core/src/platform/index.ts create mode 100644 packages/backend-core/src/platform/platformDb.ts create mode 100644 packages/backend-core/src/platform/tenants.ts create mode 100644 packages/backend-core/src/platform/tests/tenants.spec.ts create mode 100644 packages/backend-core/src/platform/users.ts create mode 100644 packages/backend-core/src/tenancy/db.ts create mode 100644 packages/backend-core/tests/utilities/DBTestConfiguration.ts delete mode 100644 packages/backend-core/tests/utilities/db.ts create mode 100644 packages/worker/src/sdk/tenants/index.ts create mode 100644 packages/worker/src/sdk/tenants/tenants.ts diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index e20798f3ac..ac87025303 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -18,7 +18,7 @@ "build:pro": "../../scripts/pro/build.sh", "postbuild": "yarn run build:pro", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", - "test": "jest --coverage --maxWorkers=2", + "test": "jest --coverage", "test:watch": "jest --watchAll" }, "dependencies": { @@ -62,7 +62,7 @@ "@trendyol/jest-testcontainers": "^2.1.1", "@types/chance": "1.1.3", "@types/ioredis": "4.28.0", - "@types/jest": "27.5.1", + "@types/jest": "28.1.1", "@types/koa": "2.13.4", "@types/koa-pino-logger": "3.0.0", "@types/lodash": "4.14.180", diff --git a/packages/backend-core/src/cache/tests/writethrough.spec.js b/packages/backend-core/src/cache/tests/writethrough.spec.js deleted file mode 100644 index fefca30c18..0000000000 --- a/packages/backend-core/src/cache/tests/writethrough.spec.js +++ /dev/null @@ -1,61 +0,0 @@ -require("../../../tests") -const { Writethrough } = require("../writethrough") -const { getDB } = require("../../db") -const tk = require("timekeeper") -const { structures } = require("../../../tests") - -const START_DATE = Date.now() -tk.freeze(START_DATE) - - -const DELAY = 5000 - -const db = getDB(structures.db.id()) -const db2 = getDB(structures.db.id()) -const writethrough = new Writethrough(db, DELAY), writethrough2 = new Writethrough(db2, DELAY) - -describe("writethrough", () => { - describe("put", () => { - let first - it("should be able to store, will go to DB", async () => { - const response = await writethrough.put({ _id: "test", value: 1 }) - const output = await db.get(response.id) - first = output - expect(output.value).toBe(1) - }) - - it("second put shouldn't update DB", async () => { - const response = await writethrough.put({ ...first, value: 2 }) - const output = await db.get(response.id) - expect(first._rev).toBe(output._rev) - expect(output.value).toBe(1) - }) - - it("should put it again after delay period", async () => { - tk.freeze(START_DATE + DELAY + 1) - const response = await writethrough.put({ ...first, value: 3 }) - const output = await db.get(response.id) - expect(response.rev).not.toBe(first._rev) - expect(output.value).toBe(3) - }) - }) - - describe("get", () => { - it("should be able to retrieve", async () => { - const response = await writethrough.get("test") - expect(response.value).toBe(3) - }) - }) - - describe("same doc, different databases (tenancy)", () => { - it("should be able to two different databases", async () => { - const resp1 = await writethrough.put({ _id: "db1", value: "first" }) - const resp2 = await writethrough2.put({ _id: "db1", value: "second" }) - expect(resp1.rev).toBeDefined() - expect(resp2.rev).toBeDefined() - expect((await db.get("db1")).value).toBe("first") - expect((await db2.get("db1")).value).toBe("second") - }) - }) -}) - diff --git a/packages/backend-core/src/cache/tests/writethrough.spec.ts b/packages/backend-core/src/cache/tests/writethrough.spec.ts new file mode 100644 index 0000000000..d346788121 --- /dev/null +++ b/packages/backend-core/src/cache/tests/writethrough.spec.ts @@ -0,0 +1,73 @@ +import { structures, DBTestConfiguration } from "../../../tests" +import { Writethrough } from "../writethrough" +import { getDB } from "../../db" +import tk from "timekeeper" + +const START_DATE = Date.now() +tk.freeze(START_DATE) + +const DELAY = 5000 + +describe("writethrough", () => { + const config = new DBTestConfiguration() + + const db = getDB(structures.db.id()) + const db2 = getDB(structures.db.id()) + + const writethrough = new Writethrough(db, DELAY) + const writethrough2 = new Writethrough(db2, DELAY) + + describe("put", () => { + let first: any + + it("should be able to store, will go to DB", async () => { + await config.doInTenant(async () => { + const response = await writethrough.put({ _id: "test", value: 1 }) + const output = await db.get(response.id) + first = output + expect(output.value).toBe(1) + }) + }) + + it("second put shouldn't update DB", async () => { + await config.doInTenant(async () => { + const response = await writethrough.put({ ...first, value: 2 }) + const output = await db.get(response.id) + expect(first._rev).toBe(output._rev) + expect(output.value).toBe(1) + }) + }) + + it("should put it again after delay period", async () => { + await config.doInTenant(async () => { + tk.freeze(START_DATE + DELAY + 1) + const response = await writethrough.put({ ...first, value: 3 }) + const output = await db.get(response.id) + expect(response.rev).not.toBe(first._rev) + expect(output.value).toBe(3) + }) + }) + }) + + describe("get", () => { + it("should be able to retrieve", async () => { + await config.doInTenant(async () => { + const response = await writethrough.get("test") + expect(response.value).toBe(3) + }) + }) + }) + + describe("same doc, different databases (tenancy)", () => { + it("should be able to two different databases", async () => { + await config.doInTenant(async () => { + const resp1 = await writethrough.put({ _id: "db1", value: "first" }) + const resp2 = await writethrough2.put({ _id: "db1", value: "second" }) + expect(resp1.rev).toBeDefined() + expect(resp2.rev).toBeDefined() + expect((await db.get("db1")).value).toBe("first") + expect((await db2.get("db1")).value).toBe("second") + }) + }) + }) +}) diff --git a/packages/backend-core/src/cache/user.ts b/packages/backend-core/src/cache/user.ts index a128465cd6..b514c3af9b 100644 --- a/packages/backend-core/src/cache/user.ts +++ b/packages/backend-core/src/cache/user.ts @@ -1,8 +1,9 @@ import * as redis from "../redis/init" -import { getTenantId, lookupTenantId, doWithGlobalDB } from "../tenancy" +import * as tenancy from "../tenancy" +import * as context from "../context" +import * as platform from "../platform" import env from "../environment" -import * as accounts from "../cloud/accounts" -import { Database } from "@budibase/types" +import * as accounts from "../accounts" const EXPIRY_SECONDS = 3600 @@ -10,7 +11,8 @@ const EXPIRY_SECONDS = 3600 * The default populate user function */ async function populateFromDB(userId: string, tenantId: string) { - const user = await doWithGlobalDB(tenantId, (db: Database) => db.get(userId)) + const db = tenancy.getTenantDB(tenantId) + const user = await db.get(userId) user.budibaseAccess = true if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { const account = await accounts.getAccount(user.email) @@ -42,9 +44,9 @@ export async function getUser( } if (!tenantId) { try { - tenantId = getTenantId() + tenantId = context.getTenantId() } catch (err) { - tenantId = await lookupTenantId(userId) + tenantId = await platform.users.lookupTenantId(userId) } } const client = await redis.getUserClient() diff --git a/packages/backend-core/src/context/deprovision.ts b/packages/backend-core/src/context/deprovision.ts deleted file mode 100644 index 81f03096dc..0000000000 --- a/packages/backend-core/src/context/deprovision.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - getGlobalUserParams, - getAllApps, - doWithDB, - StaticDatabases, -} from "../db" -import { doWithGlobalDB } from "../tenancy" -import { App, Tenants, User, Database } from "@budibase/types" - -const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants -const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name - -async function removeTenantFromInfoDB(tenantId: string) { - try { - await doWithDB(PLATFORM_INFO_DB, async (infoDb: Database) => { - const tenants = (await infoDb.get(TENANT_DOC)) as Tenants - tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId) - - await infoDb.put(tenants) - }) - } catch (err) { - console.error(`Error removing tenant ${tenantId} from info db`, err) - throw err - } -} - -export async function removeUserFromInfoDB(dbUser: User) { - await doWithDB(PLATFORM_INFO_DB, async (infoDb: Database) => { - const keys = [dbUser._id!, dbUser.email] - const userDocs = await infoDb.allDocs({ - keys, - include_docs: true, - }) - const toDelete = userDocs.rows.map((row: any) => { - return { - ...row.doc, - _deleted: true, - } - }) - await infoDb.bulkDocs(toDelete) - }) -} - -async function removeUsersFromInfoDB(tenantId: string) { - return doWithGlobalDB(tenantId, async (db: any) => { - try { - const allUsers = await db.allDocs( - getGlobalUserParams(null, { - include_docs: true, - }) - ) - await doWithDB(PLATFORM_INFO_DB, async (infoDb: any) => { - const allEmails = allUsers.rows.map((row: any) => row.doc.email) - // get the id docs - let keys = allUsers.rows.map((row: any) => row.id) - // and the email docs - keys = keys.concat(allEmails) - // retrieve the docs and delete them - const userDocs = await infoDb.allDocs({ - keys, - include_docs: true, - }) - const toDelete = userDocs.rows.map((row: any) => { - return { - ...row.doc, - _deleted: true, - } - }) - await infoDb.bulkDocs(toDelete) - }) - } catch (err) { - console.error(`Error removing tenant ${tenantId} users from info db`, err) - throw err - } - }) -} - -async function removeGlobalDB(tenantId: string) { - return doWithGlobalDB(tenantId, async (db: Database) => { - try { - await db.destroy() - } catch (err) { - console.error(`Error removing tenant ${tenantId} users from info db`, err) - throw err - } - }) -} - -async function removeTenantApps(tenantId: string) { - try { - const apps = (await getAllApps({ all: true })) as App[] - const destroyPromises = apps.map(app => - doWithDB(app.appId, (db: Database) => db.destroy()) - ) - await Promise.allSettled(destroyPromises) - } catch (err) { - console.error(`Error removing tenant ${tenantId} apps`, err) - throw err - } -} - -// can't live in tenancy package due to circular dependency on db/utils -export async function deleteTenant(tenantId: string) { - await removeTenantFromInfoDB(tenantId) - await removeUsersFromInfoDB(tenantId) - await removeGlobalDB(tenantId) - await removeTenantApps(tenantId) -} diff --git a/packages/backend-core/src/context/tests/index.spec.ts b/packages/backend-core/src/context/tests/index.spec.ts index c9b5870ffa..5c8ce6fc19 100644 --- a/packages/backend-core/src/context/tests/index.spec.ts +++ b/packages/backend-core/src/context/tests/index.spec.ts @@ -1,11 +1,14 @@ -require("../../../tests") +import { testEnv } from "../../../tests" const context = require("../") const { DEFAULT_TENANT_ID } = require("../../constants") -import env from "../../environment" describe("context", () => { describe("doInTenant", () => { describe("single-tenancy", () => { + beforeAll(() => { + testEnv.singleTenant() + }) + it("defaults to the default tenant", () => { const tenantId = context.getTenantId() expect(tenantId).toBe(DEFAULT_TENANT_ID) @@ -20,8 +23,8 @@ describe("context", () => { }) describe("multi-tenancy", () => { - beforeEach(() => { - env._set("MULTI_TENANCY", 1) + beforeAll(() => { + testEnv.multiTenant() }) it("fails when no tenant id is set", () => { diff --git a/packages/backend-core/src/db/db.ts b/packages/backend-core/src/db/db.ts index bd6b5e13c1..f13eb9a965 100644 --- a/packages/backend-core/src/db/db.ts +++ b/packages/backend-core/src/db/db.ts @@ -1,7 +1,6 @@ import env from "../environment" -import { directCouchQuery, getPouchDB } from "./couch" +import { directCouchQuery, DatabaseImpl } from "./couch" import { CouchFindOptions, Database } from "@budibase/types" -import { DatabaseImpl } from "../db" const dbList = new Set() diff --git a/packages/backend-core/src/db/tests/utils.seq.spec.ts b/packages/backend-core/src/db/tests/utils.seq.spec.ts deleted file mode 100644 index 83253402f7..0000000000 --- a/packages/backend-core/src/db/tests/utils.seq.spec.ts +++ /dev/null @@ -1,190 +0,0 @@ -require("../../../tests") -const { - getDevelopmentAppID, - getProdAppID, - isDevAppID, - isProdAppID, -} = require("../conversions") -const { generateAppID, getPlatformUrl, getScopedConfig } = require("../utils") -const tenancy = require("../../tenancy") -const { Config, DEFAULT_TENANT_ID } = require("../../constants") -import { generator } from "../../../tests" -import env from "../../environment" - -describe("utils", () => { - describe("app ID manipulation", () => { - function getID() { - const appId = generateAppID() - const split = appId.split("_") - const uuid = split[split.length - 1] - const devAppId = `app_dev_${uuid}` - return { appId, devAppId, split, uuid } - } - - it("should be able to generate a new app ID", () => { - expect(generateAppID().startsWith("app_")).toEqual(true) - }) - - it("should be able to convert a production app ID to development", () => { - const { appId, uuid } = getID() - expect(getDevelopmentAppID(appId)).toEqual(`app_dev_${uuid}`) - }) - - it("should be able to convert a development app ID to development", () => { - const { devAppId, uuid } = getID() - expect(getDevelopmentAppID(devAppId)).toEqual(`app_dev_${uuid}`) - }) - - it("should be able to convert a development ID to a production", () => { - const { devAppId, uuid } = getID() - expect(getProdAppID(devAppId)).toEqual(`app_${uuid}`) - }) - - it("should be able to convert a production ID to production", () => { - const { appId, uuid } = getID() - expect(getProdAppID(appId)).toEqual(`app_${uuid}`) - }) - - it("should be able to confirm dev app ID is development", () => { - const { devAppId } = getID() - expect(isDevAppID(devAppId)).toEqual(true) - }) - - it("should be able to confirm prod app ID is not development", () => { - const { appId } = getID() - expect(isDevAppID(appId)).toEqual(false) - }) - - it("should be able to confirm prod app ID is prod", () => { - const { appId } = getID() - expect(isProdAppID(appId)).toEqual(true) - }) - - it("should be able to confirm dev app ID is not prod", () => { - const { devAppId } = getID() - expect(isProdAppID(devAppId)).toEqual(false) - }) - }) -}) - -const DEFAULT_URL = "http://localhost:10000" -const ENV_URL = "http://env.com" - -const setDbPlatformUrl = async (dbUrl: string) => { - const db = tenancy.getGlobalDB() - await db.put({ - _id: "config_settings", - type: Config.SETTINGS, - config: { - platformUrl: dbUrl, - }, - }) -} - -const clearSettingsConfig = async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - const db = tenancy.getGlobalDB() - try { - const config = await db.get("config_settings") - await db.remove("config_settings", config._rev) - } catch (e: any) { - if (e.status !== 404) { - throw e - } - } - }) -} - -describe("getPlatformUrl", () => { - describe("self host", () => { - beforeEach(async () => { - env._set("SELF_HOST", 1) - await clearSettingsConfig() - }) - - it("gets the default url", async () => { - await tenancy.doInTenant(null, async () => { - const url = await getPlatformUrl() - expect(url).toBe(DEFAULT_URL) - }) - }) - - it("gets the platform url from the environment", async () => { - await tenancy.doInTenant(null, async () => { - env._set("PLATFORM_URL", ENV_URL) - const url = await getPlatformUrl() - expect(url).toBe(ENV_URL) - }) - }) - - it("gets the platform url from the database", async () => { - await tenancy.doInTenant(null, async () => { - const dbUrl = generator.url() - await setDbPlatformUrl(dbUrl) - const url = await getPlatformUrl() - expect(url).toBe(dbUrl) - }) - }) - }) - - describe("cloud", () => { - const TENANT_AWARE_URL = "http://default.env.com" - - beforeEach(async () => { - env._set("SELF_HOSTED", 0) - env._set("MULTI_TENANCY", 1) - env._set("PLATFORM_URL", ENV_URL) - await clearSettingsConfig() - }) - - it("gets the platform url from the environment without tenancy", async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - const url = await getPlatformUrl({ tenantAware: false }) - expect(url).toBe(ENV_URL) - }) - }) - - it("gets the platform url from the environment with tenancy", async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - const url = await getPlatformUrl() - expect(url).toBe(TENANT_AWARE_URL) - }) - }) - - it("never gets the platform url from the database", async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - await setDbPlatformUrl(generator.url()) - const url = await getPlatformUrl() - expect(url).toBe(TENANT_AWARE_URL) - }) - }) - }) -}) - -describe("getScopedConfig", () => { - describe("settings config", () => { - beforeEach(async () => { - env._set("SELF_HOSTED", 1) - env._set("PLATFORM_URL", "") - await clearSettingsConfig() - }) - - it("returns the platform url with an existing config", async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - const dbUrl = generator.url() - await setDbPlatformUrl(dbUrl) - const db = tenancy.getGlobalDB() - const config = await getScopedConfig(db, { type: Config.SETTINGS }) - expect(config.platformUrl).toBe(dbUrl) - }) - }) - - it("returns the platform url without an existing config", async () => { - await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { - const db = tenancy.getGlobalDB() - const config = await getScopedConfig(db, { type: Config.SETTINGS }) - expect(config.platformUrl).toBe(DEFAULT_URL) - }) - }) - }) -}) diff --git a/packages/backend-core/src/db/tests/utils.spec.ts b/packages/backend-core/src/db/tests/utils.spec.ts new file mode 100644 index 0000000000..7bdca5ae8b --- /dev/null +++ b/packages/backend-core/src/db/tests/utils.spec.ts @@ -0,0 +1,192 @@ +import { generator, DBTestConfiguration, testEnv } from "../../../tests" +import { + getDevelopmentAppID, + getProdAppID, + isDevAppID, + isProdAppID, +} from "../conversions" +import { generateAppID, getPlatformUrl, getScopedConfig } from "../utils" +import * as context from "../../context" +import { Config } from "../../constants" +import env from "../../environment" + +describe("utils", () => { + const config = new DBTestConfiguration() + + describe("app ID manipulation", () => { + function getID() { + const appId = generateAppID() + const split = appId.split("_") + const uuid = split[split.length - 1] + const devAppId = `app_dev_${uuid}` + return { appId, devAppId, split, uuid } + } + + it("should be able to generate a new app ID", () => { + expect(generateAppID().startsWith("app_")).toEqual(true) + }) + + it("should be able to convert a production app ID to development", () => { + const { appId, uuid } = getID() + expect(getDevelopmentAppID(appId)).toEqual(`app_dev_${uuid}`) + }) + + it("should be able to convert a development app ID to development", () => { + const { devAppId, uuid } = getID() + expect(getDevelopmentAppID(devAppId)).toEqual(`app_dev_${uuid}`) + }) + + it("should be able to convert a development ID to a production", () => { + const { devAppId, uuid } = getID() + expect(getProdAppID(devAppId)).toEqual(`app_${uuid}`) + }) + + it("should be able to convert a production ID to production", () => { + const { appId, uuid } = getID() + expect(getProdAppID(appId)).toEqual(`app_${uuid}`) + }) + + it("should be able to confirm dev app ID is development", () => { + const { devAppId } = getID() + expect(isDevAppID(devAppId)).toEqual(true) + }) + + it("should be able to confirm prod app ID is not development", () => { + const { appId } = getID() + expect(isDevAppID(appId)).toEqual(false) + }) + + it("should be able to confirm prod app ID is prod", () => { + const { appId } = getID() + expect(isProdAppID(appId)).toEqual(true) + }) + + it("should be able to confirm dev app ID is not prod", () => { + const { devAppId } = getID() + expect(isProdAppID(devAppId)).toEqual(false) + }) + }) + + const DEFAULT_URL = "http://localhost:10000" + const ENV_URL = "http://env.com" + + const setDbPlatformUrl = async (dbUrl: string) => { + const db = context.getGlobalDB() + await db.put({ + _id: "config_settings", + type: Config.SETTINGS, + config: { + platformUrl: dbUrl, + }, + }) + } + + const clearSettingsConfig = async () => { + await config.doInTenant(async () => { + const db = context.getGlobalDB() + try { + const config = await db.get("config_settings") + await db.remove("config_settings", config._rev) + } catch (e: any) { + if (e.status !== 404) { + throw e + } + } + }) + } + + describe("getPlatformUrl", () => { + describe("self host", () => { + beforeEach(async () => { + testEnv.selfHosted() + await clearSettingsConfig() + }) + + it("gets the default url", async () => { + await config.doInTenant(async () => { + const url = await getPlatformUrl() + expect(url).toBe(DEFAULT_URL) + }) + }) + + it("gets the platform url from the environment", async () => { + await config.doInTenant(async () => { + env._set("PLATFORM_URL", ENV_URL) + const url = await getPlatformUrl() + expect(url).toBe(ENV_URL) + }) + }) + + it("gets the platform url from the database", async () => { + await config.doInTenant(async () => { + const dbUrl = generator.url() + await setDbPlatformUrl(dbUrl) + const url = await getPlatformUrl() + expect(url).toBe(dbUrl) + }) + }) + }) + + describe("cloud", () => { + const TENANT_AWARE_URL = `http://${config.tenantId}.env.com` + + beforeEach(async () => { + testEnv.cloudHosted() + testEnv.multiTenant() + + env._set("PLATFORM_URL", ENV_URL) + await clearSettingsConfig() + }) + + it("gets the platform url from the environment without tenancy", async () => { + await config.doInTenant(async () => { + const url = await getPlatformUrl({ tenantAware: false }) + expect(url).toBe(ENV_URL) + }) + }) + + it("gets the platform url from the environment with tenancy", async () => { + await config.doInTenant(async () => { + const url = await getPlatformUrl() + expect(url).toBe(TENANT_AWARE_URL) + }) + }) + + it("never gets the platform url from the database", async () => { + await config.doInTenant(async () => { + await setDbPlatformUrl(generator.url()) + const url = await getPlatformUrl() + expect(url).toBe(TENANT_AWARE_URL) + }) + }) + }) + }) + + describe("getScopedConfig", () => { + describe("settings config", () => { + beforeEach(async () => { + env._set("SELF_HOSTED", 1) + env._set("PLATFORM_URL", "") + await clearSettingsConfig() + }) + + it("returns the platform url with an existing config", async () => { + await config.doInTenant(async () => { + const dbUrl = generator.url() + await setDbPlatformUrl(dbUrl) + const db = context.getGlobalDB() + const config = await getScopedConfig(db, { type: Config.SETTINGS }) + expect(config.platformUrl).toBe(dbUrl) + }) + }) + + it("returns the platform url without an existing config", async () => { + await config.doInTenant(async () => { + const db = context.getGlobalDB() + const config = await getScopedConfig(db, { type: Config.SETTINGS }) + expect(config.platformUrl).toBe(DEFAULT_URL) + }) + }) + }) + }) +}) diff --git a/packages/backend-core/src/db/views.ts b/packages/backend-core/src/db/views.ts index 4a87be0a68..8a2c2e7efd 100644 --- a/packages/backend-core/src/db/views.ts +++ b/packages/backend-core/src/db/views.ts @@ -1,13 +1,14 @@ import { - DocumentType, - ViewName, DeprecatedViews, + DocumentType, SEPARATOR, StaticDatabases, + ViewName, } from "../constants" import { getGlobalDB } from "../context" import { doWithDB } from "./" import { Database, DatabaseQueryOpts } from "@budibase/types" +import env from "../environment" const DESIGN_DB = "_design/database" @@ -69,17 +70,6 @@ export const createNewUserEmailView = async () => { await createView(db, viewJs, ViewName.USER_BY_EMAIL) } -export const createAccountEmailView = async () => { - const viewJs = `function(doc) { - if (doc._id.startsWith("${DocumentType.ACCOUNT_METADATA}${SEPARATOR}")) { - emit(doc.email.toLowerCase(), doc._id) - } - }` - await doWithDB(StaticDatabases.PLATFORM_INFO.name, async (db: Database) => { - await createView(db, viewJs, ViewName.ACCOUNT_BY_EMAIL) - }) -} - export const createUserAppView = async () => { const db = getGlobalDB() const viewJs = `function(doc) { @@ -113,17 +103,6 @@ export const createUserBuildersView = async () => { await createView(db, viewJs, ViewName.USER_BY_BUILDERS) } -export const createPlatformUserView = async () => { - const viewJs = `function(doc) { - if (doc.tenantId) { - emit(doc._id.toLowerCase(), doc._id) - } - }` - await doWithDB(StaticDatabases.PLATFORM_INFO.name, async (db: Database) => { - await createView(db, viewJs, ViewName.PLATFORM_USERS_LOWERCASE) - }) -} - export interface QueryViewOptions { arrayResponse?: boolean } @@ -162,13 +141,48 @@ export const queryView = async ( } } +// PLATFORM + +async function createPlatformView(viewJs: string, viewName: ViewName) { + try { + await doWithDB(StaticDatabases.PLATFORM_INFO.name, async (db: Database) => { + await createView(db, viewJs, viewName) + }) + } catch (e: any) { + if (e.status === 409 && env.isTest()) { + // multiple tests can try to initialise platforms views + // at once - safe to exit on conflict + return + } + throw e + } +} + +export const createPlatformAccountEmailView = async () => { + const viewJs = `function(doc) { + if (doc._id.startsWith("${DocumentType.ACCOUNT_METADATA}${SEPARATOR}")) { + emit(doc.email.toLowerCase(), doc._id) + } + }` + await createPlatformView(viewJs, ViewName.ACCOUNT_BY_EMAIL) +} + +export const createPlatformUserView = async () => { + const viewJs = `function(doc) { + if (doc.tenantId) { + emit(doc._id.toLowerCase(), doc._id) + } + }` + await createPlatformView(viewJs, ViewName.PLATFORM_USERS_LOWERCASE) +} + export const queryPlatformView = async ( viewName: ViewName, params: DatabaseQueryOpts, opts?: QueryViewOptions ): Promise => { const CreateFuncByName: any = { - [ViewName.ACCOUNT_BY_EMAIL]: createAccountEmailView, + [ViewName.ACCOUNT_BY_EMAIL]: createPlatformAccountEmailView, [ViewName.PLATFORM_USERS_LOWERCASE]: createPlatformUserView, } diff --git a/packages/backend-core/src/events/analytics.ts b/packages/backend-core/src/events/analytics.ts index f621a9c98b..7fbc6d9c2b 100644 --- a/packages/backend-core/src/events/analytics.ts +++ b/packages/backend-core/src/events/analytics.ts @@ -1,5 +1,5 @@ import env from "../environment" -import * as tenancy from "../tenancy" +import * as context from "../context" import * as dbUtils from "../db/utils" import { Config } from "../constants" import { withCache, TTL, CacheKey } from "../cache" @@ -42,7 +42,7 @@ export const enabled = async () => { } const getSettingsDoc = async () => { - const db = tenancy.getGlobalDB() + const db = context.getGlobalDB() let settings try { settings = await db.get(dbUtils.generateConfigID({ type: Config.SETTINGS })) diff --git a/packages/backend-core/src/events/processors/posthog/tests/PosthogProcessor.spec.ts b/packages/backend-core/src/events/processors/posthog/tests/PosthogProcessor.spec.ts index 349a0427ac..2c1340d36e 100644 --- a/packages/backend-core/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +++ b/packages/backend-core/src/events/processors/posthog/tests/PosthogProcessor.spec.ts @@ -1,4 +1,4 @@ -import "../../../../../tests" +import { testEnv } from "../../../../../tests" import PosthogProcessor from "../PosthogProcessor" import { Event, IdentityType, Hosting } from "@budibase/types" const tk = require("timekeeper") @@ -16,6 +16,10 @@ const newIdentity = () => { } describe("PosthogProcessor", () => { + beforeAll(() => { + testEnv.singleTenant() + }) + beforeEach(async () => { jest.clearAllMocks() await cache.bustCache( diff --git a/packages/backend-core/src/featureFlags/index.ts b/packages/backend-core/src/featureFlags/index.ts index 34ee3599a5..877cd60e1a 100644 --- a/packages/backend-core/src/featureFlags/index.ts +++ b/packages/backend-core/src/featureFlags/index.ts @@ -1,5 +1,5 @@ import env from "../environment" -import * as tenancy from "../tenancy" +import * as context from "../context" /** * Read the TENANT_FEATURE_FLAGS env var and return an array of features flags for each tenant. @@ -28,7 +28,7 @@ export function buildFeatureFlags() { } export function isEnabled(featureFlag: string) { - const tenantId = tenancy.getTenantId() + const tenantId = context.getTenantId() const flags = getTenantFeatureFlags(tenantId) return flags.includes(featureFlag) } diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index b38a53e9e4..d507d8175f 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -3,12 +3,11 @@ export * as migrations from "./migrations" export * as users from "./users" export * as roles from "./security/roles" export * as permissions from "./security/permissions" -export * as accounts from "./cloud/accounts" +export * as accounts from "./accounts" export * as installation from "./installation" -export * as tenancy from "./tenancy" export * as featureFlags from "./featureFlags" export * as sessions from "./security/sessions" -export * as deprovisioning from "./context/deprovision" +export * as platform from "./platform" export * as auth from "./auth" export * as constants from "./constants" export * as logging from "./logging" @@ -21,20 +20,27 @@ export * as context from "./context" export * as cache from "./cache" export * as objectStore from "./objectStore" export * as redis from "./redis" +export * as locks from "./redis/redlock" export * as utils from "./utils" export * as errors from "./errors" export { default as env } from "./environment" +// Add context to tenancy for backwards compatibility +// only do this for external usages to prevent internal +// circular dependencies +import * as context from "./context" +import * as _tenancy from "./tenancy" +export const tenancy = { + ..._tenancy, + ...context, +} + // expose error classes directly export * from "./errors" // expose constants directly export * from "./constants" -// expose inner locks from redis directly -import * as redis from "./redis" -export const locks = redis.redlock - // expose package init function import * as db from "./db" export const init = (opts: any = {}) => { diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index 3b5e9ae162..4bb2aaba76 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -4,7 +4,7 @@ import { getUser } from "../cache/user" import { getSession, updateSessionTTL } from "../security/sessions" import { buildMatcherRegex, matches } from "./matchers" import { SEPARATOR, queryGlobalView, ViewName } from "../db" -import { getGlobalDB, doInTenant } from "../tenancy" +import { getGlobalDB, doInTenant } from "../context" import { decrypt } from "../security/encryption" import * as identity from "../context/identity" import env from "../environment" diff --git a/packages/backend-core/src/middleware/passport/utils.ts b/packages/backend-core/src/middleware/passport/utils.ts index 3d79aada28..6eb3bc29d1 100644 --- a/packages/backend-core/src/middleware/passport/utils.ts +++ b/packages/backend-core/src/middleware/passport/utils.ts @@ -1,6 +1,6 @@ -import { isMultiTenant, getTenantId } from "../../tenancy" +import { isMultiTenant, getTenantId } from "../../context" import { getScopedConfig } from "../../db" -import { ConfigType, Database, Config } from "@budibase/types" +import { ConfigType, Database } from "@budibase/types" /** * Utility to handle authentication errors. diff --git a/packages/backend-core/src/middleware/tenancy.ts b/packages/backend-core/src/middleware/tenancy.ts index a09c463045..22b7cc213d 100644 --- a/packages/backend-core/src/middleware/tenancy.ts +++ b/packages/backend-core/src/middleware/tenancy.ts @@ -1,4 +1,5 @@ -import { doInTenant, getTenantIDFromCtx } from "../tenancy" +import { doInTenant } from "../context" +import { getTenantIDFromCtx } from "../tenancy" import { buildMatcherRegex, matches } from "./matchers" import { Header } from "../constants" import { diff --git a/packages/backend-core/src/migrations/migrations.ts b/packages/backend-core/src/migrations/migrations.ts index 55b8ab1938..79c7eb55ea 100644 --- a/packages/backend-core/src/migrations/migrations.ts +++ b/packages/backend-core/src/migrations/migrations.ts @@ -7,7 +7,7 @@ import { doWithDB, } from "../db" import environment from "../environment" -import { doInTenant, getTenantIds, getTenantId } from "../tenancy" +import * as platform from "../platform" import * as context from "../context" import { DEFINITIONS } from "." import { @@ -47,7 +47,7 @@ export const runMigration = async ( const migrationType = migration.type let tenantId: string | undefined if (migrationType !== MigrationType.INSTALLATION) { - tenantId = getTenantId() + tenantId = context.getTenantId() } const migrationName = migration.name const silent = migration.silent @@ -160,7 +160,7 @@ export const runMigrations = async ( tenantIds = [options.noOp.tenantId] } else if (!options.tenantIds || !options.tenantIds.length) { // run for all tenants - tenantIds = await getTenantIds() + tenantIds = await platform.tenants.getTenantIds() } else { tenantIds = options.tenantIds } @@ -185,7 +185,7 @@ export const runMigrations = async ( // for all migrations for (const migration of migrations) { // run the migration - await doInTenant(tenantId, () => runMigration(migration, options)) + await context.doInTenant(tenantId, () => runMigration(migration, options)) } } console.log("Migrations complete") diff --git a/packages/backend-core/src/objectStore/buckets/global.ts b/packages/backend-core/src/objectStore/buckets/global.ts index 8bf883b11e..69e201bb98 100644 --- a/packages/backend-core/src/objectStore/buckets/global.ts +++ b/packages/backend-core/src/objectStore/buckets/global.ts @@ -1,5 +1,5 @@ import env from "../../environment" -import * as tenancy from "../../tenancy" +import * as context from "../../context" import * as objectStore from "../objectStore" import * as cloudfront from "../cloudfront" @@ -22,7 +22,7 @@ export const getGlobalFileUrl = (type: string, name: string, etag?: string) => { export const getGlobalFileS3Key = (type: string, name: string) => { let file = `${type}/${name}` if (env.MULTI_TENANCY) { - const tenantId = tenancy.getTenantId() + const tenantId = context.getTenantId() file = `${tenantId}/${file}` } return file diff --git a/packages/backend-core/src/objectStore/buckets/plugins.ts b/packages/backend-core/src/objectStore/buckets/plugins.ts index cd3bf77e87..f7721afb23 100644 --- a/packages/backend-core/src/objectStore/buckets/plugins.ts +++ b/packages/backend-core/src/objectStore/buckets/plugins.ts @@ -1,6 +1,6 @@ import env from "../../environment" import * as objectStore from "../objectStore" -import * as tenancy from "../../tenancy" +import * as context from "../../context" import * as cloudfront from "../cloudfront" import { Plugin } from "@budibase/types" @@ -61,7 +61,7 @@ const getPluginS3Key = (plugin: Plugin, fileName: string) => { export const getPluginS3Dir = (pluginName: string) => { let s3Key = `${pluginName}` if (env.MULTI_TENANCY) { - const tenantId = tenancy.getTenantId() + const tenantId = context.getTenantId() s3Key = `${tenantId}/${s3Key}` } if (env.CLOUDFRONT_CDN) { diff --git a/packages/backend-core/src/platform/index.ts b/packages/backend-core/src/platform/index.ts new file mode 100644 index 0000000000..877d85ade0 --- /dev/null +++ b/packages/backend-core/src/platform/index.ts @@ -0,0 +1,3 @@ +export * as users from "./users" +export * as tenants from "./tenants" +export * from "./platformDb" diff --git a/packages/backend-core/src/platform/platformDb.ts b/packages/backend-core/src/platform/platformDb.ts new file mode 100644 index 0000000000..90b683dd33 --- /dev/null +++ b/packages/backend-core/src/platform/platformDb.ts @@ -0,0 +1,6 @@ +import { StaticDatabases } from "../constants" +import { getDB } from "../db/db" + +export function getPlatformDB() { + return getDB(StaticDatabases.PLATFORM_INFO.name) +} diff --git a/packages/backend-core/src/platform/tenants.ts b/packages/backend-core/src/platform/tenants.ts new file mode 100644 index 0000000000..b9f946a735 --- /dev/null +++ b/packages/backend-core/src/platform/tenants.ts @@ -0,0 +1,101 @@ +import { StaticDatabases } from "../constants" +import { getPlatformDB } from "./platformDb" +import { LockName, LockOptions, LockType, Tenants } from "@budibase/types" +import * as locks from "../redis/redlock" + +const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants + +export const tenacyLockOptions: LockOptions = { + type: LockType.DEFAULT, + name: LockName.UPDATE_TENANTS_DOC, + ttl: 10 * 1000, // auto expire after 10 seconds + systemLock: true, +} + +// READ + +export async function getTenantIds(): Promise { + const tenants = await getTenants() + return tenants.tenantIds +} + +async function getTenants(): Promise { + const db = getPlatformDB() + let tenants: Tenants + + try { + tenants = await db.get(TENANT_DOC) + } catch (e: any) { + // doesn't exist yet - create + if (e.status === 404) { + tenants = await createTenantsDoc() + } else { + throw e + } + } + + return tenants +} + +export async function exists(tenantId: string) { + const tenants = await getTenants() + return tenants.tenantIds.indexOf(tenantId) !== -1 +} + +// CREATE / UPDATE + +function newTenantsDoc(): Tenants { + return { + _id: TENANT_DOC, + tenantIds: [], + } +} + +async function createTenantsDoc(): Promise { + const db = getPlatformDB() + let tenants = newTenantsDoc() + + try { + const response = await db.put(tenants) + tenants._rev = response.rev + } catch (e: any) { + // don't throw 409 is doc has already been created + if (e.status === 409) { + return db.get(TENANT_DOC) + } + throw e + } + + return tenants +} + +export async function addTenant(tenantId: string) { + const db = getPlatformDB() + + // use a lock as tenant creation is conflict prone + await locks.doWithLock(tenacyLockOptions, async () => { + const tenants = await getTenants() + + // write the new tenant if it doesn't already exist + if (tenants.tenantIds.indexOf(tenantId) === -1) { + tenants.tenantIds.push(tenantId) + await db.put(tenants) + } + }) +} + +// DELETE + +export async function removeTenant(tenantId: string) { + try { + await locks.doWithLock(tenacyLockOptions, async () => { + const db = getPlatformDB() + const tenants = await getTenants() + tenants.tenantIds = tenants.tenantIds.filter(id => id !== tenantId) + await db.put(tenants) + }) + } catch (err) { + console.error(`Error removing tenant ${tenantId} from info db`, err) + throw err + } +} diff --git a/packages/backend-core/src/platform/tests/tenants.spec.ts b/packages/backend-core/src/platform/tests/tenants.spec.ts new file mode 100644 index 0000000000..92e999cb2d --- /dev/null +++ b/packages/backend-core/src/platform/tests/tenants.spec.ts @@ -0,0 +1,25 @@ +import { DBTestConfiguration, structures } from "../../../tests" +import * as tenants from "../tenants" + +describe("tenants", () => { + const config = new DBTestConfiguration() + + describe("addTenant", () => { + it("concurrently adds multiple tenants safely", async () => { + const tenant1 = structures.tenant.id() + const tenant2 = structures.tenant.id() + const tenant3 = structures.tenant.id() + + await Promise.all([ + tenants.addTenant(tenant1), + tenants.addTenant(tenant2), + tenants.addTenant(tenant3), + ]) + + const tenantIds = await tenants.getTenantIds() + expect(tenantIds.includes(tenant1)).toBe(true) + expect(tenantIds.includes(tenant2)).toBe(true) + expect(tenantIds.includes(tenant3)).toBe(true) + }) + }) +}) diff --git a/packages/backend-core/src/platform/users.ts b/packages/backend-core/src/platform/users.ts new file mode 100644 index 0000000000..c65a7e0ec4 --- /dev/null +++ b/packages/backend-core/src/platform/users.ts @@ -0,0 +1,90 @@ +import { getPlatformDB } from "./platformDb" +import { DEFAULT_TENANT_ID } from "../constants" +import env from "../environment" +import { + PlatformUser, + PlatformUserByEmail, + PlatformUserById, + User, +} from "@budibase/types" + +// READ + +export async function lookupTenantId(userId: string) { + if (!env.MULTI_TENANCY) { + return DEFAULT_TENANT_ID + } + + const user = await getUserDoc(userId) + return user.tenantId +} + +async function getUserDoc(emailOrId: string): Promise { + const db = getPlatformDB() + return db.get(emailOrId) +} + +// CREATE + +function newUserIdDoc(id: string, tenantId: string): PlatformUserById { + return { + _id: id, + tenantId, + } +} + +function newUserEmailDoc( + userId: string, + email: string, + tenantId: string +): PlatformUserByEmail { + return { + _id: email, + userId, + tenantId, + } +} + +/** + * Add a new user id or email doc if it doesn't exist. + */ +async function addUserDoc(emailOrId: string, newDocFn: () => PlatformUser) { + const db = getPlatformDB() + let user: PlatformUser + + try { + await db.get(emailOrId) + } catch (e: any) { + if (e.status === 404) { + user = newDocFn() + await db.put(user) + } else { + throw e + } + } +} + +export async function addUser(tenantId: string, userId: string, email: string) { + await Promise.all([ + addUserDoc(userId, () => newUserIdDoc(userId, tenantId)), + addUserDoc(email, () => newUserEmailDoc(userId, email, tenantId)), + ]) +} + +// DELETE + +export async function removeUser(user: User) { + const db = getPlatformDB() + const keys = [user._id!, user.email] + const userDocs = await db.allDocs({ + keys, + include_docs: true, + }) + const toDelete = userDocs.rows.map((row: any) => { + return { + ...row.doc, + _deleted: true, + } + }) + await db.bulkDocs(toDelete) +} diff --git a/packages/backend-core/src/redis/index.ts b/packages/backend-core/src/redis/index.ts index ea4379f048..5bf2c65c39 100644 --- a/packages/backend-core/src/redis/index.ts +++ b/packages/backend-core/src/redis/index.ts @@ -3,4 +3,4 @@ export { default as Client } from "./redis" export * as utils from "./utils" export * as clients from "./init" -export * as redlock from "./redlock" +export * as locks from "./redlock" diff --git a/packages/backend-core/src/redis/redlock.ts b/packages/backend-core/src/redis/redlock.ts index 54b2c0a8d1..2021da2b56 100644 --- a/packages/backend-core/src/redis/redlock.ts +++ b/packages/backend-core/src/redis/redlock.ts @@ -1,29 +1,22 @@ import Redlock, { Options } from "redlock" import { getLockClient } from "./init" import { LockOptions, LockType } from "@budibase/types" -import * as tenancy from "../tenancy" - -let noRetryRedlock: Redlock | undefined +import * as context from "../context" +import env from "../environment" const getClient = async (type: LockType): Promise => { + if (env.isTest() && type !== LockType.TRY_ONCE) { + return newRedlock(OPTIONS.TEST) + } switch (type) { case LockType.TRY_ONCE: { - if (!noRetryRedlock) { - noRetryRedlock = await newRedlock(OPTIONS.TRY_ONCE) - } - return noRetryRedlock + return newRedlock(OPTIONS.TRY_ONCE) } case LockType.DEFAULT: { - if (!noRetryRedlock) { - noRetryRedlock = await newRedlock(OPTIONS.DEFAULT) - } - return noRetryRedlock + return newRedlock(OPTIONS.DEFAULT) } case LockType.DELAY_500: { - if (!noRetryRedlock) { - noRetryRedlock = await newRedlock(OPTIONS.DELAY_500) - } - return noRetryRedlock + return newRedlock(OPTIONS.DELAY_500) } default: { throw new Error(`Could not get redlock client: ${type}`) @@ -36,6 +29,11 @@ export const OPTIONS = { // immediately throws an error if the lock is already held retryCount: 0, }, + TEST: { + // higher retry count in unit tests + // due to high contention. + retryCount: 100, + }, DEFAULT: { // the expected clock drift; for more details // see http://redis.io/topics/distlock @@ -69,12 +67,19 @@ export const doWithLock = async (opts: LockOptions, task: any) => { const redlock = await getClient(opts.type) let lock try { - // aquire lock - let name: string = `lock:${tenancy.getTenantId()}_${opts.name}` + // determine lock name + // by default use the tenantId for uniqueness, unless using a system lock + const prefix = opts.systemLock ? "system" : context.getTenantId() + let name: string = `lock:${prefix}_${opts.name}` + + // add additional unique name if required if (opts.nameSuffix) { name = name + `_${opts.nameSuffix}` } + + // create the lock lock = await redlock.lock(name, opts.ttl) + // perform locked task // need to await to ensure completion before unlocking const result = await task() diff --git a/packages/backend-core/src/tenancy/db.ts b/packages/backend-core/src/tenancy/db.ts new file mode 100644 index 0000000000..10477a8579 --- /dev/null +++ b/packages/backend-core/src/tenancy/db.ts @@ -0,0 +1,6 @@ +import { getDB } from "../db/db" +import { getGlobalDBName } from "../context" + +export function getTenantDB(tenantId: string) { + return getDB(getGlobalDBName(tenantId)) +} diff --git a/packages/backend-core/src/tenancy/index.ts b/packages/backend-core/src/tenancy/index.ts index 1618a136dd..3f17e33271 100644 --- a/packages/backend-core/src/tenancy/index.ts +++ b/packages/backend-core/src/tenancy/index.ts @@ -1,2 +1,2 @@ -export * from "../context" +export * from "./db" export * from "./tenancy" diff --git a/packages/backend-core/src/tenancy/tenancy.ts b/packages/backend-core/src/tenancy/tenancy.ts index 732402bcb7..e8ddf88226 100644 --- a/packages/backend-core/src/tenancy/tenancy.ts +++ b/packages/backend-core/src/tenancy/tenancy.ts @@ -1,4 +1,3 @@ -import { doWithDB, getGlobalDBName } from "../db" import { DEFAULT_TENANT_ID, getTenantId, @@ -11,10 +10,7 @@ import { TenantResolutionStrategy, GetTenantIdOptions, } from "@budibase/types" -import { Header, StaticDatabases } from "../constants" - -const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants -const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name +import { Header } from "../constants" export function addTenantToUrl(url: string) { const tenantId = getTenantId() @@ -27,89 +23,6 @@ export function addTenantToUrl(url: string) { return url } -export async function doesTenantExist(tenantId: string) { - return doWithDB(PLATFORM_INFO_DB, async (db: any) => { - let tenants - try { - tenants = await db.get(TENANT_DOC) - } catch (err) { - // if theres an error the doc doesn't exist, no tenants exist - return false - } - return ( - tenants && - Array.isArray(tenants.tenantIds) && - tenants.tenantIds.indexOf(tenantId) !== -1 - ) - }) -} - -export async function tryAddTenant( - tenantId: string, - userId: string, - email: string, - afterCreateTenant: () => Promise -) { - return doWithDB(PLATFORM_INFO_DB, async (db: any) => { - const getDoc = async (id: string) => { - if (!id) { - return null - } - try { - return await db.get(id) - } catch (err) { - return { _id: id } - } - } - let [tenants, userIdDoc, emailDoc] = await Promise.all([ - getDoc(TENANT_DOC), - getDoc(userId), - getDoc(email), - ]) - if (!Array.isArray(tenants.tenantIds)) { - tenants = { - _id: TENANT_DOC, - tenantIds: [], - } - } - let promises = [] - if (userIdDoc) { - userIdDoc.tenantId = tenantId - promises.push(db.put(userIdDoc)) - } - if (emailDoc) { - emailDoc.tenantId = tenantId - emailDoc.userId = userId - promises.push(db.put(emailDoc)) - } - if (tenants.tenantIds.indexOf(tenantId) === -1) { - tenants.tenantIds.push(tenantId) - promises.push(db.put(tenants)) - await afterCreateTenant() - } - await Promise.all(promises) - }) -} - -export function doWithGlobalDB(tenantId: string, cb: any) { - return doWithDB(getGlobalDBName(tenantId), cb) -} - -export async function lookupTenantId(userId: string) { - return doWithDB(StaticDatabases.PLATFORM_INFO.name, async (db: any) => { - let tenantId = env.MULTI_TENANCY ? DEFAULT_TENANT_ID : null - try { - const doc = await db.get(userId) - if (doc && doc.tenantId) { - tenantId = doc.tenantId - } - } catch (err) { - // just return the default - } - return tenantId - }) -} - export const isUserInAppTenant = (appId: string, user?: any) => { let userTenantId if (user) { @@ -121,19 +34,6 @@ export const isUserInAppTenant = (appId: string, user?: any) => { return tenantId === userTenantId } -export async function getTenantIds() { - return doWithDB(PLATFORM_INFO_DB, async (db: any) => { - let tenants - try { - tenants = await db.get(TENANT_DOC) - } catch (err) { - // if theres an error the doc doesn't exist, no tenants exist - return [] - } - return (tenants && tenants.tenantIds) || [] - }) -} - const ALL_STRATEGIES = Object.values(TenantResolutionStrategy) export const getTenantIDFromCtx = ( diff --git a/packages/backend-core/src/utils/tests/utils.spec.ts b/packages/backend-core/src/utils/tests/utils.spec.ts index b3cd527fb3..7d6c5561e8 100644 --- a/packages/backend-core/src/utils/tests/utils.spec.ts +++ b/packages/backend-core/src/utils/tests/utils.spec.ts @@ -1,21 +1,12 @@ -import { structures } from "../../../tests" +import { structures, DBTestConfiguration } from "../../../tests" import * as utils from "../../utils" -import * as events from "../../events" import * as db from "../../db" import { Header } from "../../constants" -import { doInTenant } from "../../context" import { newid } from "../../utils" +import env from "../../environment" describe("utils", () => { - describe("platformLogout", () => { - it("should call platform logout", async () => { - await doInTenant(structures.tenant.id(), async () => { - const ctx = structures.koa.newContext() - await utils.platformLogout({ ctx, userId: "test" }) - expect(events.auth.logout).toBeCalledTimes(1) - }) - }) - }) + const config = new DBTestConfiguration() describe("getAppIdFromCtx", () => { it("gets appId from header", async () => { @@ -50,21 +41,28 @@ describe("utils", () => { }) it("gets appId from url", async () => { - const ctx = structures.koa.newContext() - const expected = db.generateAppID() - const app = structures.apps.app(expected) + await config.doInTenant(async () => { + const url = "http://test.com" + env._set("PLATFORM_URL", url) - // set custom url - const appUrl = newid() - app.url = `/${appUrl}` - ctx.path = `/app/${appUrl}` + const ctx = structures.koa.newContext() + ctx.host = `${config.tenantId}.test.com` - // save the app - const database = db.getDB(expected) - await database.put(app) + const expected = db.generateAppID(config.tenantId) + const app = structures.apps.app(expected) - const actual = await utils.getAppIdFromCtx(ctx) - expect(actual).toBe(expected) + // set custom url + const appUrl = newid() + app.url = `/${appUrl}` + ctx.path = `/app/${appUrl}` + + // save the app + const database = db.getDB(expected) + await database.put(app) + + const actual = await utils.getAppIdFromCtx(ctx) + expect(actual).toBe(expected) + }) }) it("doesn't get appId from url when previewing", async () => { diff --git a/packages/backend-core/tests/utilities/DBTestConfiguration.ts b/packages/backend-core/tests/utilities/DBTestConfiguration.ts new file mode 100644 index 0000000000..cad62e2979 --- /dev/null +++ b/packages/backend-core/tests/utilities/DBTestConfiguration.ts @@ -0,0 +1,32 @@ +import "./mocks" +import * as structures from "./structures" +import * as testEnv from "./testEnv" +import * as context from "../../src/context" + +class DBTestConfiguration { + tenantId: string + + constructor() { + // db tests need to be multi tenant to prevent conflicts + testEnv.multiTenant() + this.tenantId = structures.tenant.id() + } + + // TENANCY + + doInTenant(task: any) { + return context.doInTenant(this.tenantId, () => { + return task() + }) + } + + getTenantId() { + try { + return context.getTenantId() + } catch (e) { + return this.tenantId! + } + } +} + +export default DBTestConfiguration diff --git a/packages/backend-core/tests/utilities/db.ts b/packages/backend-core/tests/utilities/db.ts deleted file mode 100644 index 84b77bb201..0000000000 --- a/packages/backend-core/tests/utilities/db.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as db from "../../src/db" - -const dbConfig = { - inMemory: true, -} - -export const init = () => { - db.init(dbConfig) -} diff --git a/packages/backend-core/tests/utilities/index.ts b/packages/backend-core/tests/utilities/index.ts index 468d980a7f..efe014908b 100644 --- a/packages/backend-core/tests/utilities/index.ts +++ b/packages/backend-core/tests/utilities/index.ts @@ -4,5 +4,4 @@ export { generator } from "./structures" export * as testEnv from "./testEnv" export * as testContainerUtils from "./testContainerUtils" -import * as dbConfig from "./db" -dbConfig.init() +export { default as DBTestConfiguration } from "./DBTestConfiguration" diff --git a/packages/backend-core/tests/utilities/testEnv.ts b/packages/backend-core/tests/utilities/testEnv.ts index b4f06b5153..b138e019fc 100644 --- a/packages/backend-core/tests/utilities/testEnv.ts +++ b/packages/backend-core/tests/utilities/testEnv.ts @@ -1,12 +1,12 @@ import env from "../../src/environment" -import * as tenancy from "../../src/tenancy" -import { newid } from "../../src/utils" +import * as context from "../../src/context" +import * as structures from "./structures" // TENANCY export async function withTenant(task: (tenantId: string) => any) { - const tenantId = newid() - return tenancy.doInTenant(tenantId, async () => { + const tenantId = structures.tenant.id() + return context.doInTenant(tenantId, async () => { await task(tenantId) }) } @@ -19,6 +19,14 @@ export function multiTenant() { env._set("MULTI_TENANCY", 1) } +export function selfHosted() { + env._set("SELF_HOSTED", 1) +} + +export function cloudHosted() { + env._set("SELF_HOSTED", 0) +} + // NODE export function nodeDev() { diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index d88b1058f9..5f8edb3df6 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -1197,10 +1197,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.1.tgz#2c8b6dc6ff85c33bcd07d0b62cb3d19ddfdb3ab9" - integrity sha512-fUy7YRpT+rHXto1YlL+J9rs0uLGyiqVt3ZOTQR+4ROc47yNl8WLdVLgUloBRhOxP1PZvguHl44T3H0wAWxahYQ== +"@types/jest@28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.1.tgz#8c9ba63702a11f8c386ee211280e8b68cb093cd1" + integrity sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA== dependencies: jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" diff --git a/packages/server/package.json b/packages/server/package.json index 391a5f326f..cfc5fa9fa3 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -141,6 +141,7 @@ "@types/pouchdb": "6.4.0", "@types/redis": "4.0.11", "@types/server-destroy": "1.0.1", + "@types/supertest": "2.0.12", "@types/tar": "6.1.3", "@typescript-eslint/parser": "5.45.0", "apidoc": "0.50.4", @@ -159,7 +160,7 @@ "path-to-regexp": "6.2.0", "prettier": "2.5.1", "rimraf": "3.0.2", - "supertest": "4.0.2", + "supertest": "6.2.2", "swagger-jsdoc": "6.1.0", "timekeeper": "2.2.0", "ts-jest": "28.0.4", diff --git a/packages/server/src/api/routes/tests/backup.spec.ts b/packages/server/src/api/routes/tests/backup.spec.ts index 7b325c080d..ef362ef403 100644 --- a/packages/server/src/api/routes/tests/backup.spec.ts +++ b/packages/server/src/api/routes/tests/backup.spec.ts @@ -19,7 +19,6 @@ describe("/backups", () => { .get(`/api/backups/export?appId=${config.getAppId()}&appname=test`) .set(config.defaultHeaders()) .expect(200) - expect(res.text).toBeDefined() expect(res.headers["content-type"]).toEqual("application/gzip") expect(events.app.exported).toBeCalledTimes(1) }) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 5c45f89a2b..29a5f07607 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -236,42 +236,41 @@ class TestConfiguration { email = this.defaultUserValues.email, roles, }: any = {}) { - return tenancy.doWithGlobalDB(this.getTenantId(), async (db: Database) => { - let existing - try { - existing = await db.get(id) - } catch (err) { - existing = { email } - } - const user = { - _id: id, - ...existing, - roles: roles || {}, - tenantId: this.getTenantId(), - firstName, - lastName, - } - await sessions.createASession(id, { - sessionId: "sessionid", - tenantId: this.getTenantId(), - csrfToken: this.defaultUserValues.csrfToken, - }) - if (builder) { - user.builder = { global: true } - } else { - user.builder = { global: false } - } - if (admin) { - user.admin = { global: true } - } else { - user.admin = { global: false } - } - const resp = await db.put(user) - return { - _rev: resp.rev, - ...user, - } + const db = tenancy.getTenantDB(this.getTenantId()) + let existing + try { + existing = await db.get(id) + } catch (err) { + existing = { email } + } + const user = { + _id: id, + ...existing, + roles: roles || {}, + tenantId: this.getTenantId(), + firstName, + lastName, + } + await sessions.createASession(id, { + sessionId: "sessionid", + tenantId: this.getTenantId(), + csrfToken: this.defaultUserValues.csrfToken, }) + if (builder) { + user.builder = { global: true } + } else { + user.builder = { global: false } + } + if (admin) { + user.admin = { global: true } + } else { + user.admin = { global: false } + } + const resp = await db.put(user) + return { + _rev: resp.rev, + ...user, + } } async createUser( @@ -407,20 +406,19 @@ class TestConfiguration { // API async generateApiKey(userId = this.defaultUserValues.globalUserId) { - return tenancy.doWithGlobalDB(this.getTenantId(), async (db: any) => { - const id = dbCore.generateDevInfoID(userId) - let devInfo - try { - devInfo = await db.get(id) - } catch (err) { - devInfo = { _id: id, userId } - } - devInfo.apiKey = encryption.encrypt( - `${this.getTenantId()}${dbCore.SEPARATOR}${newid()}` - ) - await db.put(devInfo) - return devInfo.apiKey - }) + const db = tenancy.getTenantDB(this.getTenantId()) + const id = dbCore.generateDevInfoID(userId) + let devInfo + try { + devInfo = await db.get(id) + } catch (err) { + devInfo = { _id: id, userId } + } + devInfo.apiKey = encryption.encrypt( + `${this.getTenantId()}${dbCore.SEPARATOR}${newid()}` + ) + await db.put(devInfo) + return devInfo.apiKey } // APP diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 4982b57131..c3fc7b0bbe 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -3547,6 +3547,14 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/superagent@*": + version "4.1.16" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.16.tgz#12c9c16f232f9d89beab91d69368f96ce8e2d881" + integrity sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + "@types/superagent@^4.1.12": version "4.1.15" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.15.tgz#63297de457eba5e2bc502a7609426c4cceab434a" @@ -3555,6 +3563,13 @@ "@types/cookiejar" "*" "@types/node" "*" +"@types/supertest@2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" + integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== + dependencies: + "@types/superagent" "*" + "@types/tar@6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.3.tgz#46a2ce7617950c4852dfd7e9cd41aa8161b9d750" @@ -4241,7 +4256,7 @@ arrify@^2.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -asap@^2.0.3: +asap@^2.0.0, asap@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== @@ -5416,7 +5431,7 @@ commoner@^0.10.1: q "^1.1.2" recast "^0.11.17" -component-emitter@^1.2.0, component-emitter@^1.2.1: +component-emitter@^1.2.1, component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -5518,7 +5533,7 @@ cookie@^0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookiejar@^2.1.0: +cookiejar@^2.1.3: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== @@ -5967,6 +5982,14 @@ detective@^4.3.1: acorn "^5.2.1" defined "^1.0.0" +dezalgo@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" + integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== + dependencies: + asap "^2.0.0" + wrappy "1" + diff-match-patch@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" @@ -6061,11 +6084,6 @@ dotenv@16.0.1: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== -dotenv@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== - dotenv@^8.2.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" @@ -6888,7 +6906,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: +extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -6977,7 +6995,7 @@ fast-redact@^3.0.0: resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.1.tgz#790fcff8f808c2e12fabbfb2be5cb2deda448fa0" integrity sha512-odVmjC8x8jNeMZ3C+rPMESzXVSEU8tSWSHv9HFxP2mm89G/1WwqhrerJDQm9Zus8X6aoRgQDThKqptdNA6bt+A== -fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8: +fast-safe-stringify@^2.0.7, fast-safe-stringify@^2.0.8, fast-safe-stringify@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== @@ -7264,7 +7282,7 @@ form-data@4.0.0, form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@^2.3.1, form-data@^2.5.0: +form-data@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== @@ -7291,11 +7309,21 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -formidable@^1.1.1, formidable@^1.2.0: +formidable@^1.1.1: version "1.2.6" resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168" integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== +formidable@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.1.tgz#81269cbea1a613240049f5f61a9d97731517414f" + integrity sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ== + dependencies: + dezalgo "^1.0.4" + hexoid "^1.0.0" + once "^1.4.0" + qs "^6.11.0" + forwarded-parse@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/forwarded-parse/-/forwarded-parse-2.1.2.tgz#08511eddaaa2ddfd56ba11138eee7df117a09325" @@ -7947,6 +7975,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hexoid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -10703,7 +10736,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@^1.1.1, methods@^1.1.2: +methods@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -10755,7 +10788,12 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.24, mime-types@^2.1.27, dependencies: mime-db "1.52.0" -mime@^1.3.4, mime@^1.4.1: +mime@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mime@^1.3.4: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -12502,14 +12540,14 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@^6.11.0: +qs@^6.10.3, qs@^6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" -qs@^6.4.0, qs@^6.5.1: +qs@^6.4.0: version "6.10.5" resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.5.tgz#974715920a80ff6a262264acd2c7e6c2a53282b4" integrity sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ== @@ -13990,29 +14028,30 @@ sublevel-pouchdb@7.2.2: ltgt "2.2.1" readable-stream "1.1.14" -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== +superagent@^7.1.0: + version "7.1.6" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-7.1.6.tgz#64f303ed4e4aba1e9da319f134107a54cacdc9c6" + integrity sha512-gZkVCQR1gy/oUXr+kxJMLDjla434KmSOKbx5iGD30Ql+AkJQ/YlPKECJy2nhqOsHLjGHzoDTXNSjhnvWhzKk7g== dependencies: - component-emitter "^1.2.0" - cookiejar "^2.1.0" - debug "^3.1.0" - extend "^3.0.0" - form-data "^2.3.1" - formidable "^1.2.0" - methods "^1.1.1" - mime "^1.4.1" - qs "^6.5.1" - readable-stream "^2.3.5" + component-emitter "^1.3.0" + cookiejar "^2.1.3" + debug "^4.3.4" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^2.0.1" + methods "^1.1.2" + mime "2.6.0" + qs "^6.10.3" + readable-stream "^3.6.0" + semver "^7.3.7" -supertest@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" - integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== +supertest@6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.2.2.tgz#04a5998fd3efaff187cb69f07a169755d655b001" + integrity sha512-wCw9WhAtKJsBvh07RaS+/By91NNE0Wh0DN19/hWPlBOU8tAfOtbZoVSV4xXeoKoxgPx0rx2y+y+8660XtE7jzg== dependencies: methods "^1.1.2" - superagent "^3.8.3" + superagent "^7.1.0" supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" diff --git a/packages/types/src/sdk/locks.ts b/packages/types/src/sdk/locks.ts index e6809319b1..d868691891 100644 --- a/packages/types/src/sdk/locks.ts +++ b/packages/types/src/sdk/locks.ts @@ -12,6 +12,7 @@ export enum LockName { MIGRATIONS = "migrations", TRIGGER_QUOTA = "trigger_quota", SYNC_ACCOUNT_LICENSE = "sync_account_license", + UPDATE_TENANTS_DOC = "update_tenants_doc", } export interface LockOptions { diff --git a/packages/worker/package.json b/packages/worker/package.json index 9a55f527df..061a44c958 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -22,7 +22,7 @@ "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", "dev:builder": "npm run dev:stack:init && nodemon", - "test": "jest --coverage --maxWorkers=2", + "test": "jest --coverage", "test:watch": "jest --watch", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", @@ -73,7 +73,7 @@ "@swc/core": "^1.3.25", "@swc/jest": "^0.2.24", "@trendyol/jest-testcontainers": "^2.1.1", - "@types/jest": "26.0.23", + "@types/jest": "28.1.1", "@types/jsonwebtoken": "8.5.1", "@types/koa": "2.13.4", "@types/koa__router": "8.0.8", @@ -81,6 +81,7 @@ "@types/node-fetch": "2.6.1", "@types/pouchdb": "6.4.0", "@types/server-destroy": "1.0.1", + "@types/supertest": "2.0.12", "@types/uuid": "8.3.4", "@typescript-eslint/parser": "5.45.0", "copyfiles": "2.4.1", diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 817480151d..43ec23eade 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -1,5 +1,5 @@ import { checkInviteCode } from "../../../utilities/redis" -import sdk from "../../../sdk" +import * as userSdk from "../../../sdk/users" import env from "../../../environment" import { BulkUserRequest, @@ -8,6 +8,7 @@ import { CreateAdminUserRequest, InviteUserRequest, InviteUsersRequest, + MigrationType, SearchUsersRequest, User, } from "@budibase/types" @@ -16,7 +17,9 @@ import { cache, errors, events, + migrations, tenancy, + platform, } from "@budibase/backend-core" import { checkAnyUserExists } from "../../../utilities/users" @@ -25,7 +28,7 @@ const MAX_USERS_UPLOAD_LIMIT = 1000 export const save = async (ctx: any) => { try { const currentUserId = ctx.user._id - ctx.body = await sdk.users.save(ctx.request.body, { currentUserId }) + ctx.body = await userSdk.save(ctx.request.body, { currentUserId }) } catch (err: any) { ctx.throw(err.status || 400, err) } @@ -35,7 +38,7 @@ const bulkDelete = async (userIds: string[], currentUserId: string) => { if (userIds?.indexOf(currentUserId) !== -1) { throw new Error("Unable to delete self.") } - return await sdk.users.bulkDelete(userIds) + return await userSdk.bulkDelete(userIds) } const bulkCreate = async (users: User[], groupIds: string[]) => { @@ -44,7 +47,7 @@ const bulkCreate = async (users: User[], groupIds: string[]) => { "Max limit for upload is 1000 users. Please reduce file size and try again." ) } - return await sdk.users.bulkCreate(users, groupIds) + return await userSdk.bulkCreate(users, groupIds) } export const bulkUpdate = async (ctx: any) => { @@ -71,16 +74,26 @@ const parseBooleanParam = (param: any) => { export const adminUser = async (ctx: any) => { const { email, password, tenantId } = ctx.request .body as CreateAdminUserRequest + + if (await platform.tenants.exists(tenantId)) { + ctx.throw(403, "Organisation already exists.") + } + + if (env.MULTI_TENANCY) { + // store the new tenant record in the platform db + await platform.tenants.addTenant(tenantId) + await migrations.backPopulateMigrations({ + type: MigrationType.GLOBAL, + tenantId, + }) + } + await tenancy.doInTenant(tenantId, async () => { // account portal sends a pre-hashed password - honour param to prevent double hashing const hashPassword = parseBooleanParam(ctx.request.query.hashPassword) // account portal sends no password for SSO users const requirePassword = parseBooleanParam(ctx.request.query.requirePassword) - if (await tenancy.doesTenantExist(tenantId)) { - ctx.throw(403, "Organisation already exists.") - } - const userExists = await checkAnyUserExists() if (userExists) { ctx.throw( @@ -106,7 +119,7 @@ export const adminUser = async (ctx: any) => { // always bust checklist beforehand, if an error occurs but can proceed, don't get // stuck in a cycle await cache.bustCache(cache.CacheKey.CHECKLIST) - const finalUser = await sdk.users.save(user, { + const finalUser = await userSdk.save(user, { hashPassword, requirePassword, }) @@ -128,7 +141,7 @@ export const adminUser = async (ctx: any) => { export const countByApp = async (ctx: any) => { const appId = ctx.params.appId try { - ctx.body = await sdk.users.countUsersByApp(appId) + ctx.body = await userSdk.countUsersByApp(appId) } catch (err: any) { ctx.throw(err.status || 400, err) } @@ -140,7 +153,7 @@ export const destroy = async (ctx: any) => { ctx.throw(400, "Unable to delete self.") } - await sdk.users.destroy(id, ctx.user) + await userSdk.destroy(id, ctx.user) ctx.body = { message: `User ${id} deleted.`, @@ -149,7 +162,7 @@ export const destroy = async (ctx: any) => { export const search = async (ctx: any) => { const body = ctx.request.body as SearchUsersRequest - const paginated = await sdk.users.paginatedUsers(body) + const paginated = await userSdk.paginatedUsers(body) // user hashed password shouldn't ever be returned for (let user of paginated.data) { if (user) { @@ -161,7 +174,7 @@ export const search = async (ctx: any) => { // called internally by app server user fetch export const fetch = async (ctx: any) => { - const all = await sdk.users.allUsers() + const all = await userSdk.allUsers() // user hashed password shouldn't ever be returned for (let user of all) { if (user) { @@ -173,12 +186,12 @@ export const fetch = async (ctx: any) => { // called internally by app server user find export const find = async (ctx: any) => { - ctx.body = await sdk.users.getUser(ctx.params.id) + ctx.body = await userSdk.getUser(ctx.params.id) } export const tenantUserLookup = async (ctx: any) => { const id = ctx.params.id - const user = await sdk.users.getPlatformUser(id) + const user = await userSdk.getPlatformUser(id) if (user) { ctx.body = user } else { @@ -188,7 +201,7 @@ export const tenantUserLookup = async (ctx: any) => { export const invite = async (ctx: any) => { const request = ctx.request.body as InviteUserRequest - const response = await sdk.users.invite([request]) + const response = await userSdk.invite([request]) // explicitly throw for single user invite if (response.unsuccessful.length) { @@ -207,7 +220,7 @@ export const invite = async (ctx: any) => { export const inviteMultiple = async (ctx: any) => { const request = ctx.request.body as InviteUsersRequest - ctx.body = await sdk.users.invite(request) + ctx.body = await userSdk.invite(request) } export const checkInvite = async (ctx: any) => { @@ -229,7 +242,7 @@ export const inviteAccept = async (ctx: any) => { // info is an extension of the user object that was stored by global const { email, info }: any = await checkInviteCode(inviteCode) ctx.body = await tenancy.doInTenant(info.tenantId, async () => { - const saved = await sdk.users.save({ + const saved = await userSdk.save({ firstName, lastName, password, diff --git a/packages/worker/src/api/controllers/system/tenants.ts b/packages/worker/src/api/controllers/system/tenants.ts index 6916049534..151507358f 100644 --- a/packages/worker/src/api/controllers/system/tenants.ts +++ b/packages/worker/src/api/controllers/system/tenants.ts @@ -1,8 +1,7 @@ -import { BBContext } from "@budibase/types" -import { deprovisioning } from "@budibase/backend-core" -import { quotas } from "@budibase/pro" +import { UserCtx } from "@budibase/types" +import * as tenantSdk from "../../../sdk/tenants" -const _delete = async (ctx: BBContext) => { +export async function destroy(ctx: UserCtx) { const user = ctx.user! const tenantId = ctx.params.tenantId @@ -11,13 +10,10 @@ const _delete = async (ctx: BBContext) => { } try { - await quotas.bustCache() - await deprovisioning.deleteTenant(tenantId) + await tenantSdk.deleteTenant(tenantId) ctx.status = 204 } catch (err) { ctx.log.error(err) throw err } } - -export { _delete as delete } diff --git a/packages/worker/src/api/routes/global/tests/configs.spec.ts b/packages/worker/src/api/routes/global/tests/configs.spec.ts index ee27c4d451..39ad74d295 100644 --- a/packages/worker/src/api/routes/global/tests/configs.spec.ts +++ b/packages/worker/src/api/routes/global/tests/configs.spec.ts @@ -2,7 +2,7 @@ jest.mock("nodemailer") import { TestConfiguration, structures, mocks } from "../../../../tests" mocks.email.mock() -import { Config, context, events } from "@budibase/backend-core" +import { Config, events } from "@budibase/backend-core" describe("configs", () => { const config = new TestConfiguration() @@ -113,64 +113,56 @@ describe("configs", () => { describe("create", () => { it("should create activated OIDC config", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - await saveOIDCConfig() - expect(events.auth.SSOCreated).toBeCalledTimes(1) - expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC) - expect(events.auth.SSODeactivated).not.toBeCalled() - expect(events.auth.SSOActivated).toBeCalledTimes(1) - expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC) - await config.deleteConfig(Config.OIDC) - }) + await saveOIDCConfig() + expect(events.auth.SSOCreated).toBeCalledTimes(1) + expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC) + expect(events.auth.SSODeactivated).not.toBeCalled() + expect(events.auth.SSOActivated).toBeCalledTimes(1) + expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC) + await config.deleteConfig(Config.OIDC) }) it("should create deactivated OIDC config", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - await saveOIDCConfig({ activated: false }) - expect(events.auth.SSOCreated).toBeCalledTimes(1) - expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC) - expect(events.auth.SSOActivated).not.toBeCalled() - expect(events.auth.SSODeactivated).not.toBeCalled() - await config.deleteConfig(Config.OIDC) - }) + await saveOIDCConfig({ activated: false }) + expect(events.auth.SSOCreated).toBeCalledTimes(1) + expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC) + expect(events.auth.SSOActivated).not.toBeCalled() + expect(events.auth.SSODeactivated).not.toBeCalled() + await config.deleteConfig(Config.OIDC) }) }) describe("update", () => { it("should update OIDC config to deactivated", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - const oidcConf = await saveOIDCConfig() - jest.clearAllMocks() - await saveOIDCConfig( - { ...oidcConf.config.configs[0], activated: false }, - oidcConf._id, - oidcConf._rev - ) - expect(events.auth.SSOUpdated).toBeCalledTimes(1) - expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC) - expect(events.auth.SSOActivated).not.toBeCalled() - expect(events.auth.SSODeactivated).toBeCalledTimes(1) - expect(events.auth.SSODeactivated).toBeCalledWith(Config.OIDC) - await config.deleteConfig(Config.OIDC) - }) + const oidcConf = await saveOIDCConfig() + jest.clearAllMocks() + await saveOIDCConfig( + { ...oidcConf.config.configs[0], activated: false }, + oidcConf._id, + oidcConf._rev + ) + expect(events.auth.SSOUpdated).toBeCalledTimes(1) + expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC) + expect(events.auth.SSOActivated).not.toBeCalled() + expect(events.auth.SSODeactivated).toBeCalledTimes(1) + expect(events.auth.SSODeactivated).toBeCalledWith(Config.OIDC) + await config.deleteConfig(Config.OIDC) }) it("should update OIDC config to activated", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - const oidcConf = await saveOIDCConfig({ activated: false }) - jest.clearAllMocks() - await saveOIDCConfig( - { ...oidcConf.config.configs[0], activated: true }, - oidcConf._id, - oidcConf._rev - ) - expect(events.auth.SSOUpdated).toBeCalledTimes(1) - expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC) - expect(events.auth.SSODeactivated).not.toBeCalled() - expect(events.auth.SSOActivated).toBeCalledTimes(1) - expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC) - await config.deleteConfig(Config.OIDC) - }) + const oidcConf = await saveOIDCConfig({ activated: false }) + jest.clearAllMocks() + await saveOIDCConfig( + { ...oidcConf.config.configs[0], activated: true }, + oidcConf._id, + oidcConf._rev + ) + expect(events.auth.SSOUpdated).toBeCalledTimes(1) + expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC) + expect(events.auth.SSODeactivated).not.toBeCalled() + expect(events.auth.SSOActivated).toBeCalledTimes(1) + expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC) + await config.deleteConfig(Config.OIDC) }) }) }) @@ -187,26 +179,22 @@ describe("configs", () => { describe("create", () => { it("should create SMTP config", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - await config.deleteConfig(Config.SMTP) - await saveSMTPConfig() - expect(events.email.SMTPUpdated).not.toBeCalled() - expect(events.email.SMTPCreated).toBeCalledTimes(1) - await config.deleteConfig(Config.SMTP) - }) + await config.deleteConfig(Config.SMTP) + await saveSMTPConfig() + expect(events.email.SMTPUpdated).not.toBeCalled() + expect(events.email.SMTPCreated).toBeCalledTimes(1) + await config.deleteConfig(Config.SMTP) }) }) describe("update", () => { it("should update SMTP config", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - const smtpConf = await saveSMTPConfig() - jest.clearAllMocks() - await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev) - expect(events.email.SMTPCreated).not.toBeCalled() - expect(events.email.SMTPUpdated).toBeCalledTimes(1) - await config.deleteConfig(Config.SMTP) - }) + const smtpConf = await saveSMTPConfig() + jest.clearAllMocks() + await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev) + expect(events.email.SMTPCreated).not.toBeCalled() + expect(events.email.SMTPUpdated).toBeCalledTimes(1) + await config.deleteConfig(Config.SMTP) }) }) }) @@ -223,73 +211,65 @@ describe("configs", () => { describe("create", () => { it("should create settings config with default settings", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - await config.deleteConfig(Config.SETTINGS) + await config.deleteConfig(Config.SETTINGS) - await saveSettingsConfig() + await saveSettingsConfig() - expect(events.org.nameUpdated).not.toBeCalled() - expect(events.org.logoUpdated).not.toBeCalled() - expect(events.org.platformURLUpdated).not.toBeCalled() - }) + expect(events.org.nameUpdated).not.toBeCalled() + expect(events.org.logoUpdated).not.toBeCalled() + expect(events.org.platformURLUpdated).not.toBeCalled() }) it("should create settings config with non-default settings", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - config.modeSelf() - await config.deleteConfig(Config.SETTINGS) - const conf = { - company: "acme", - logoUrl: "http://example.com", - platformUrl: "http://example.com", - } + config.selfHosted() + await config.deleteConfig(Config.SETTINGS) + const conf = { + company: "acme", + logoUrl: "http://example.com", + platformUrl: "http://example.com", + } - await saveSettingsConfig(conf) + await saveSettingsConfig(conf) - expect(events.org.nameUpdated).toBeCalledTimes(1) - expect(events.org.logoUpdated).toBeCalledTimes(1) - expect(events.org.platformURLUpdated).toBeCalledTimes(1) - config.modeCloud() - }) + expect(events.org.nameUpdated).toBeCalledTimes(1) + expect(events.org.logoUpdated).toBeCalledTimes(1) + expect(events.org.platformURLUpdated).toBeCalledTimes(1) + config.cloudHosted() }) }) describe("update", () => { it("should update settings config", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - config.modeSelf() - await config.deleteConfig(Config.SETTINGS) - const settingsConfig = await saveSettingsConfig() - settingsConfig.config.company = "acme" - settingsConfig.config.logoUrl = "http://example.com" - settingsConfig.config.platformUrl = "http://example.com" + config.selfHosted() + await config.deleteConfig(Config.SETTINGS) + const settingsConfig = await saveSettingsConfig() + settingsConfig.config.company = "acme" + settingsConfig.config.logoUrl = "http://example.com" + settingsConfig.config.platformUrl = "http://example.com" - await saveSettingsConfig( - settingsConfig.config, - settingsConfig._id, - settingsConfig._rev - ) + await saveSettingsConfig( + settingsConfig.config, + settingsConfig._id, + settingsConfig._rev + ) - expect(events.org.nameUpdated).toBeCalledTimes(1) - expect(events.org.logoUpdated).toBeCalledTimes(1) - expect(events.org.platformURLUpdated).toBeCalledTimes(1) - config.modeCloud() - }) + expect(events.org.nameUpdated).toBeCalledTimes(1) + expect(events.org.logoUpdated).toBeCalledTimes(1) + expect(events.org.platformURLUpdated).toBeCalledTimes(1) + config.cloudHosted() }) }) }) }) it("should return the correct checklist status based on the state of the budibase installation", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - await config.saveSmtpConfig() + await config.saveSmtpConfig() - const res = await config.api.configs.getConfigChecklist() - const checklist = res.body + const res = await config.api.configs.getConfigChecklist() + const checklist = res.body - expect(checklist.apps.checked).toBeFalsy() - expect(checklist.smtp.checked).toBeTruthy() - expect(checklist.adminUser.checked).toBeTruthy() - }) + expect(checklist.apps.checked).toBeFalsy() + expect(checklist.smtp.checked).toBeTruthy() + expect(checklist.adminUser.checked).toBeTruthy() }) }) diff --git a/packages/worker/src/api/routes/global/tests/roles.spec.ts b/packages/worker/src/api/routes/global/tests/roles.spec.ts index 622a643f25..477ccaf94c 100644 --- a/packages/worker/src/api/routes/global/tests/roles.spec.ts +++ b/packages/worker/src/api/routes/global/tests/roles.spec.ts @@ -32,6 +32,7 @@ async function addAppMetadata() { describe("/api/global/roles", () => { const config = new TestConfiguration() + const role = new roles.Role( db.generateRoleID("newRole"), roles.BUILTIN_ROLE_IDS.BASIC, @@ -43,13 +44,13 @@ describe("/api/global/roles", () => { }) beforeEach(async () => { - appId = db.generateAppID() + appId = db.generateAppID(config.tenantId) appDb = db.getDB(appId) const mockAppDB = context.getAppDB as Mock mockAppDB.mockReturnValue(appDb) await addAppMetadata() - appDb.put(role) + await appDb.put(role) }) afterAll(async () => { diff --git a/packages/worker/src/api/routes/global/tests/users.spec.ts b/packages/worker/src/api/routes/global/tests/users.spec.ts index a8b07ec815..31ef1d9b0c 100644 --- a/packages/worker/src/api/routes/global/tests/users.spec.ts +++ b/packages/worker/src/api/routes/global/tests/users.spec.ts @@ -3,7 +3,9 @@ import { InviteUsersResponse, User } from "@budibase/types" jest.mock("nodemailer") import { TestConfiguration, mocks, structures } from "../../../../tests" const sendMailMock = mocks.email.mock() -import { context, events, tenancy } from "@budibase/backend-core" +import { events, tenancy, accounts as _accounts } from "@budibase/backend-core" + +const accounts = jest.mocked(_accounts) describe("/api/global/users", () => { const config = new TestConfiguration() @@ -20,26 +22,24 @@ describe("/api/global/users", () => { jest.clearAllMocks() }) - describe("invite", () => { + describe("POST /api/global/users/invite", () => { it("should be able to generate an invitation", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - const email = structures.users.newEmail() - const { code, res } = await config.api.users.sendUserInvite( - sendMailMock, - email - ) + const email = structures.users.newEmail() + const { code, res } = await config.api.users.sendUserInvite( + sendMailMock, + email + ) - expect(res.body).toEqual({ message: "Invitation has been sent." }) - expect(sendMailMock).toHaveBeenCalled() - expect(code).toBeDefined() - expect(events.user.invited).toBeCalledTimes(1) - }) + expect(res.body).toEqual({ message: "Invitation has been sent." }) + expect(sendMailMock).toHaveBeenCalled() + expect(code).toBeDefined() + expect(events.user.invited).toBeCalledTimes(1) }) it("should not be able to generate an invitation for existing user", async () => { const { code, res } = await config.api.users.sendUserInvite( sendMailMock, - config.defaultUser!.email, + config.user!.email, 400 ) @@ -50,26 +50,24 @@ describe("/api/global/users", () => { }) it("should be able to create new user from invite", async () => { - await context.doInTenant(config.tenant1User!.tenantId, async () => { - const email = structures.users.newEmail() - const { code } = await config.api.users.sendUserInvite( - sendMailMock, - email - ) + const email = structures.users.newEmail() + const { code } = await config.api.users.sendUserInvite( + sendMailMock, + email + ) - const res = await config.api.users.acceptInvite(code) + const res = await config.api.users.acceptInvite(code) - expect(res.body._id).toBeDefined() - const user = await config.getUser(email) - expect(user).toBeDefined() - expect(user._id).toEqual(res.body._id) - expect(events.user.inviteAccepted).toBeCalledTimes(1) - expect(events.user.inviteAccepted).toBeCalledWith(user) - }) + expect(res.body._id).toBeDefined() + const user = await config.getUser(email) + expect(user).toBeDefined() + expect(user._id).toEqual(res.body._id) + expect(events.user.inviteAccepted).toBeCalledTimes(1) + expect(events.user.inviteAccepted).toBeCalledWith(user) }) }) - describe("inviteMultiple", () => { + describe("POST /api/global/users/multi/invite", () => { it("should be able to generate an invitation", async () => { const newUserInvite = () => ({ email: structures.users.newEmail(), @@ -87,7 +85,7 @@ describe("/api/global/users", () => { }) it("should not be able to generate an invitation for existing user", async () => { - const request = [{ email: config.defaultUser!.email, userInfo: {} }] + const request = [{ email: config.user!.email, userInfo: {} }] const res = await config.api.users.sendMultiUserInvite(request) @@ -100,7 +98,7 @@ describe("/api/global/users", () => { }) }) - describe("bulk (create)", () => { + describe("POST /api/global/users/bulk", () => { it("should ignore users existing in the same tenant", async () => { const user = await config.createUser() jest.clearAllMocks() @@ -163,7 +161,7 @@ describe("/api/global/users", () => { }) }) - describe("create", () => { + describe("POST /api/global/users", () => { it("should be able to create a basic user", async () => { const user = structures.users.user() @@ -242,7 +240,7 @@ describe("/api/global/users", () => { it("should not be able to create user with the same email as an account", async () => { const user = structures.users.user() const account = structures.accounts.cloudAccount() - mocks.accounts.getAccount.mockReturnValueOnce(account) + accounts.getAccount.mockReturnValueOnce(Promise.resolve(account)) const response = await config.api.users.saveUser(user, 400) @@ -283,7 +281,7 @@ describe("/api/global/users", () => { }) }) - describe("update", () => { + describe("POST /api/global/users (update)", () => { it("should be able to update a basic user", async () => { const user = await config.createUser() jest.clearAllMocks() @@ -298,7 +296,7 @@ describe("/api/global/users", () => { }) it("should not allow a user to update their own admin/builder status", async () => { - const user = (await config.api.users.getUser(config.defaultUser?._id!)) + const user = (await config.api.users.getUser(config.user?._id!)) .body as User await config.api.users.saveUser({ ...user, @@ -468,9 +466,9 @@ describe("/api/global/users", () => { }) }) - describe("bulk (delete)", () => { + describe("POST /api/global/users/bulk (delete)", () => { it("should not be able to bulk delete current user", async () => { - const user = await config.defaultUser! + const user = await config.user! const response = await config.api.users.bulkDeleteUsers([user._id!], 400) @@ -482,7 +480,7 @@ describe("/api/global/users", () => { const user = await config.createUser() const account = structures.accounts.cloudAccount() account.budibaseUserId = user._id! - mocks.accounts.getAccountByTenantId.mockReturnValue(account) + accounts.getAccountByTenantId.mockReturnValue(Promise.resolve(account)) const response = await config.api.users.bulkDeleteUsers([user._id!]) @@ -497,7 +495,7 @@ describe("/api/global/users", () => { it("should be able to bulk delete users", async () => { const account = structures.accounts.cloudAccount() - mocks.accounts.getAccountByTenantId.mockReturnValue(account) + accounts.getAccountByTenantId.mockReturnValue(Promise.resolve(account)) const builder = structures.users.builderUser() const admin = structures.users.adminUser() @@ -521,7 +519,7 @@ describe("/api/global/users", () => { }) }) - describe("destroy", () => { + describe("DELETE /api/global/users/:userId", () => { it("should be able to destroy a basic user", async () => { const user = await config.createUser() jest.clearAllMocks() @@ -558,7 +556,7 @@ describe("/api/global/users", () => { it("should not be able to destroy account owner", async () => { const user = await config.createUser() const account = structures.accounts.cloudAccount() - mocks.accounts.getAccount.mockReturnValueOnce(account) + accounts.getAccount.mockReturnValueOnce(Promise.resolve(account)) const response = await config.api.users.deleteUser(user._id!, 400) @@ -566,10 +564,10 @@ describe("/api/global/users", () => { }) it("should not be able to destroy account owner as account owner", async () => { - const user = await config.defaultUser! + const user = await config.user! const account = structures.accounts.cloudAccount() account.email = user.email - mocks.accounts.getAccount.mockReturnValueOnce(account) + accounts.getAccount.mockReturnValueOnce(Promise.resolve(account)) const response = await config.api.users.deleteUser(user._id!, 400) diff --git a/packages/worker/src/api/routes/system/tenants.ts b/packages/worker/src/api/routes/system/tenants.ts index 111cfc5819..234459cfdc 100644 --- a/packages/worker/src/api/routes/system/tenants.ts +++ b/packages/worker/src/api/routes/system/tenants.ts @@ -7,7 +7,7 @@ const router: Router = new Router() router.delete( "/api/system/tenants/:tenantId", middleware.adminOnly, - controller.delete + controller.destroy ) export default router diff --git a/packages/worker/src/api/routes/system/tests/restore.spec.ts b/packages/worker/src/api/routes/system/tests/restore.spec.ts index 4dd973270f..2130fd8dde 100644 --- a/packages/worker/src/api/routes/system/tests/restore.spec.ts +++ b/packages/worker/src/api/routes/system/tests/restore.spec.ts @@ -25,12 +25,12 @@ describe("/api/system/restore", () => { }) it("restores in self host", async () => { - config.modeSelf() + config.selfHosted() const res = await config.api.restore.restored() expect(res.body).toEqual({ message: "System prepared after restore.", }) - config.modeCloud() + config.cloudHosted() }) }) }) diff --git a/packages/worker/src/api/routes/system/tests/status.spec.ts b/packages/worker/src/api/routes/system/tests/status.spec.ts index afd3f8ac46..fe0ff13551 100644 --- a/packages/worker/src/api/routes/system/tests/status.spec.ts +++ b/packages/worker/src/api/routes/system/tests/status.spec.ts @@ -1,6 +1,6 @@ import { TestConfiguration } from "../../../../tests" -import { accounts } from "@budibase/backend-core" -import { mocks } from "@budibase/backend-core/tests" +import { accounts as _accounts } from "@budibase/backend-core" +const accounts = jest.mocked(_accounts) describe("/api/system/status", () => { const config = new TestConfiguration() @@ -19,7 +19,7 @@ describe("/api/system/status", () => { describe("GET /api/system/status", () => { it("returns status in self host", async () => { - config.modeSelf() + config.selfHosted() const res = await config.api.status.getStatus() expect(res.body).toEqual({ health: { @@ -27,7 +27,7 @@ describe("/api/system/status", () => { }, }) expect(accounts.getStatus).toBeCalledTimes(0) - config.modeCloud() + config.cloudHosted() }) it("returns status in cloud", async () => { @@ -37,7 +37,7 @@ describe("/api/system/status", () => { }, } - mocks.accounts.getStatus.mockReturnValueOnce(value) + accounts.getStatus.mockReturnValueOnce(Promise.resolve(value)) const res = await config.api.status.getStatus() diff --git a/packages/worker/src/migrations/functions/globalInfoSyncUsers.ts b/packages/worker/src/migrations/functions/globalInfoSyncUsers.ts index 941791fe93..1ffcc762c4 100644 --- a/packages/worker/src/migrations/functions/globalInfoSyncUsers.ts +++ b/packages/worker/src/migrations/functions/globalInfoSyncUsers.ts @@ -1,5 +1,6 @@ import { User } from "@budibase/types" -import sdk from "../../sdk" +import * as usersSdk from "../../sdk/users" +import { platform } from "@budibase/backend-core" /** * Date: @@ -9,11 +10,11 @@ import sdk from "../../sdk" * Re-sync the global-db users to the global-info db users */ export const run = async (globalDb: any) => { - const users = (await sdk.users.allUsers()) as User[] + const users = (await usersSdk.allUsers()) as User[] const promises = [] for (let user of users) { promises.push( - sdk.users.addTenant(user.tenantId, user._id as string, user.email) + platform.users.addUser(user.tenantId, user._id as string, user.email) ) } await Promise.all(promises) diff --git a/packages/worker/src/sdk/tenants/index.ts b/packages/worker/src/sdk/tenants/index.ts new file mode 100644 index 0000000000..19b7ea6615 --- /dev/null +++ b/packages/worker/src/sdk/tenants/index.ts @@ -0,0 +1 @@ +export * from "./tenants" diff --git a/packages/worker/src/sdk/tenants/tenants.ts b/packages/worker/src/sdk/tenants/tenants.ts new file mode 100644 index 0000000000..3ba9c3f3a7 --- /dev/null +++ b/packages/worker/src/sdk/tenants/tenants.ts @@ -0,0 +1,76 @@ +import { App } from "@budibase/types" +import { tenancy, db as dbCore, platform } from "@budibase/backend-core" +import { quotas } from "@budibase/pro" + +export async function deleteTenant(tenantId: string) { + await quotas.bustCache() + await platform.tenants.removeTenant(tenantId) + await removeGlobalDB(tenantId) + await removeTenantUsers(tenantId) + await removeTenantApps(tenantId) +} + +async function removeGlobalDB(tenantId: string) { + try { + const db = tenancy.getTenantDB(tenantId) + await db.destroy() + } catch (err) { + console.error(`Error removing tenant ${tenantId} users from info db`, err) + throw err + } +} + +async function removeTenantApps(tenantId: string) { + try { + const apps = (await dbCore.getAllApps({ all: true })) as App[] + const destroyPromises = apps.map(app => { + const db = dbCore.getDB(app.appId) + return db.destroy() + }) + await Promise.allSettled(destroyPromises) + } catch (err) { + console.error(`Error removing tenant ${tenantId} apps`, err) + throw err + } +} + +function getTenantUsers(tenantId: string) { + const db = tenancy.getTenantDB(tenantId) + + return db.allDocs( + dbCore.getGlobalUserParams(null, { + include_docs: true, + }) + ) +} + +async function removeTenantUsers(tenantId: string) { + try { + const allUsers = await getTenantUsers(tenantId) + const allEmails = allUsers.rows.map((row: any) => row.doc.email) + + // get the id and email doc ids + let keys = allUsers.rows.map((row: any) => row.id) + keys = keys.concat(allEmails) + + const platformDb = platform.getPlatformDB() + + // retrieve the docs + const userDocs = await platformDb.allDocs({ + keys, + include_docs: true, + }) + + // delete the docs + const toDelete = userDocs.rows.map((row: any) => { + return { + ...row.doc, + _deleted: true, + } + }) + await platformDb.bulkDocs(toDelete) + } catch (err) { + console.error(`Error removing tenant ${tenantId} users from info db`, err) + throw err + } +} diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 8410d0b2e0..330cdfde6d 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -549,7 +549,7 @@ export const bulkDelete = async ( export const destroy = async (id: string, currentUser: any) => { const db = tenancy.getGlobalDB() - const dbUser = await db.get(id) + const dbUser = (await db.get(id)) as User const userId = dbUser._id as string if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { diff --git a/packages/worker/src/tests/TestConfiguration.ts b/packages/worker/src/tests/TestConfiguration.ts index 0cc1e61e65..7d075e7fef 100644 --- a/packages/worker/src/tests/TestConfiguration.ts +++ b/packages/worker/src/tests/TestConfiguration.ts @@ -15,61 +15,29 @@ const supertest = require("supertest") import { Config } from "../constants" import { users, - tenancy, + context, sessions, auth, constants, env as coreEnv, - DEFAULT_TENANT_ID, } from "@budibase/backend-core" -import structures, { TENANT_ID, CSRF_TOKEN } from "./structures" +import structures, { CSRF_TOKEN } from "./structures" import { CreateUserResponse, User, AuthToken } from "@budibase/types" import API from "./api" -import sdk from "../sdk" - -enum Mode { - CLOUD = "cloud", - SELF = "self", -} - -async function retry any>( - fn: T, - maxTry: number = 5, - retryCount = 1 -): Promise>> { - const currRetry = typeof retryCount === "number" ? retryCount : 1 - try { - const result = await fn() - return result - } catch (e) { - console.log(`Retry ${currRetry} failed.`) - if (currRetry > maxTry) { - console.log(`All ${maxTry} retry attempts exhausted`) - throw e - } - return retry(fn, maxTry, currRetry + 1) - } -} class TestConfiguration { server: any request: any api: API - defaultUser?: User - tenant1User?: User - #tenantId?: string + tenantId: string + user?: User + userPassword = "test" - constructor( - opts: { openServer: boolean; mode: Mode } = { - openServer: true, - mode: Mode.CLOUD, - } - ) { - if (opts.mode === Mode.CLOUD) { - this.modeCloud() - } else if (opts.mode === Mode.SELF) { - this.modeSelf() - } + constructor(opts: { openServer: boolean } = { openServer: true }) { + // default to cloud hosting + this.cloudHosted() + + this.tenantId = structures.tenant.id() if (opts.openServer) { env.PORT = "0" // random port @@ -85,26 +53,19 @@ class TestConfiguration { return this.request } - // MODES - - setMultiTenancy = (value: boolean) => { - env._set("MULTI_TENANCY", value) - coreEnv._set("MULTI_TENANCY", value) - } + // HOSTING setSelfHosted = (value: boolean) => { env._set("SELF_HOSTED", value) coreEnv._set("SELF_HOSTED", value) } - modeCloud = () => { + cloudHosted = () => { this.setSelfHosted(false) - this.setMultiTenancy(true) } - modeSelf = () => { + selfHosted = () => { this.setSelfHosted(true) - this.setMultiTenancy(false) } // UTILS @@ -125,7 +86,7 @@ class TestConfiguration { if (params) { request.params = params } - await tenancy.doInTenant(this.getTenantId(), () => { + await context.doInTenant(this.getTenantId(), () => { return controlFunc(request) }) return request.body @@ -135,18 +96,10 @@ class TestConfiguration { async beforeAll() { try { - this.#tenantId = structures.tenant.id() - - // Running tests in parallel causes issues creating the globaldb twice. This ensures the db is properly created before starting - await retry(async () => await this.createDefaultUser()) - await this.createSession(this.defaultUser!) - - await tenancy.doInTenant(this.#tenantId, async () => { - await this.createTenant1User() - await this.createSession(this.tenant1User!) - }) + await this.createDefaultUser() + await this.createSession(this.user!) } catch (e: any) { - console.log(e) + console.error(e) throw new Error(e.message) } } @@ -159,12 +112,16 @@ class TestConfiguration { // TENANCY + doInTenant(task: any) { + return context.doInTenant(this.tenantId, () => { + return task() + }) + } + createTenant = async (): Promise => { // create user / new tenant const res = await this.api.users.createAdminUser() - await sdk.users.addTenant(res.tenantId, res.userId, res.email) - // return the created user const userRes = await this.api.users.getUser(res.userId, { headers: { @@ -182,9 +139,9 @@ class TestConfiguration { getTenantId() { try { - return tenancy.getTenantId() - } catch (e: any) { - return DEFAULT_TENANT_ID + return context.getTenantId() + } catch (e) { + return this.tenantId! } } @@ -232,14 +189,11 @@ class TestConfiguration { } defaultHeaders() { - const tenantId = this.getTenantId() - if (tenantId === TENANT_ID) { - return this.authHeaders(this.defaultUser!) - } else if (tenantId === this.getTenantId()) { - return this.authHeaders(this.tenant1User!) - } else { - throw new Error("could not determine auth headers to use") - } + return this.authHeaders(this.user!) + } + + tenantIdHeaders() { + return { [constants.Header.TENANT_ID]: this.tenantId } } internalAPIHeaders() { @@ -254,20 +208,15 @@ class TestConfiguration { async createDefaultUser() { const user = structures.users.adminUser({ - password: "test", + password: this.userPassword, }) - this.defaultUser = await this.createUser(user) - } - - async createTenant1User() { - const user = structures.users.adminUser({ - password: "test", + await context.doInTenant(this.tenantId!, async () => { + this.user = await this.createUser(user) }) - this.tenant1User = await this.createUser(user) } async getUser(email: string): Promise { - return tenancy.doInTenant(this.getTenantId(), () => { + return context.doInTenant(this.getTenantId(), () => { return users.getGlobalUserByEmail(email) }) } diff --git a/packages/worker/src/tests/api/base.ts b/packages/worker/src/tests/api/base.ts index c1263ed5cb..460d61e70a 100644 --- a/packages/worker/src/tests/api/base.ts +++ b/packages/worker/src/tests/api/base.ts @@ -1,4 +1,5 @@ import TestConfiguration from "../TestConfiguration" +import { SuperTest, Test } from "supertest" export interface TestAPIOpts { headers?: any @@ -7,7 +8,7 @@ export interface TestAPIOpts { export abstract class TestAPI { config: TestConfiguration - request: any + request: SuperTest protected constructor(config: TestConfiguration) { this.config = config diff --git a/packages/worker/src/tests/api/restore.ts b/packages/worker/src/tests/api/restore.ts index 6069c20185..c6a646317d 100644 --- a/packages/worker/src/tests/api/restore.ts +++ b/packages/worker/src/tests/api/restore.ts @@ -9,6 +9,7 @@ export class RestoreAPI extends TestAPI { restored = (opts?: TestAPIOpts) => { return this.request .post(`/api/system/restored`) + .set(this.config.tenantIdHeaders()) .expect(opts?.status ? opts.status : 200) } } diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index e7a02fce1f..b03e9d9d7c 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -800,17 +800,6 @@ slash "^3.0.0" write-file-atomic "^4.0.1" -"@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - "@jest/types@^27.5.1": version "27.5.1" resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" @@ -1317,6 +1306,11 @@ resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.5.tgz#650820e95de346e1f84e30667d168c8fd25aa6e3" integrity sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA== +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + "@types/cookies@*": version "0.7.7" resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.7.tgz#7a92453d1d16389c05a5301eef566f34946cfd81" @@ -1413,13 +1407,13 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@26.0.23": - version "26.0.23" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.23.tgz#a1b7eab3c503b80451d019efb588ec63522ee4e7" - integrity sha512-ZHLmWMJ9jJ9PTiT58juykZpL7KjwJywFN3Rr2pTSkyQfydf/rk22yS7W8p5DaVUMQ2BQC7oYiU3FjbTM/mYrOA== +"@types/jest@28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.1.tgz#8c9ba63702a11f8c386ee211280e8b68cb093cd1" + integrity sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA== dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" "@types/json-buffer@~3.0.0": version "3.0.0" @@ -1689,6 +1683,21 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/superagent@*": + version "4.1.16" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.16.tgz#12c9c16f232f9d89beab91d69368f96ce8e2d881" + integrity sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" + integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== + dependencies: + "@types/superagent" "*" + "@types/tough-cookie@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" @@ -1704,13 +1713,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^16.0.0": version "16.0.5" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" @@ -1898,7 +1900,7 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== -ansi-regex@^5.0.0, ansi-regex@^5.0.1: +ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== @@ -2999,10 +3001,10 @@ dezalgo@1.0.3: asap "^2.0.0" wrappy "1" -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== diff-sequences@^28.1.1: version "28.1.1" @@ -3066,11 +3068,6 @@ dotenv@16.0.1: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== -dotenv@8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - double-ended-queue@2.1.0-0: version "2.1.0-0" resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c" @@ -4727,15 +4724,15 @@ jest-config@^28.1.3: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^26.0.0: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== dependencies: chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" jest-diff@^28.1.3: version "28.1.3" @@ -4777,10 +4774,10 @@ jest-environment-node@^28.1.3: jest-mock "^28.1.3" jest-util "^28.1.3" -jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== jest-get-type@^28.0.2: version "28.0.2" @@ -4814,6 +4811,16 @@ jest-leak-detector@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" +jest-matcher-utils@^27.0.0: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + jest-matcher-utils@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" @@ -6624,14 +6631,13 @@ prettier@2.3.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6" integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA== -pretty-format@^26.0.0, pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== +pretty-format@^27.0.0, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" react-is "^17.0.1" pretty-format@^28.1.3: From 07e5598538f745b8495e5f58d7920c2d1a22fc38 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 13 Feb 2023 12:09:16 +0000 Subject: [PATCH 009/273] Enable use of redis container in worker tests --- packages/backend-core/src/environment.ts | 5 +++-- packages/backend-core/src/queue/queue.ts | 2 +- packages/backend-core/src/redis/redis.ts | 13 +++++++++---- packages/backend-core/src/redis/utils.ts | 10 ++++------ .../tests/utilities/testContainerUtils.ts | 5 +++++ 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index d742ca1cc9..95e636c9b4 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -44,8 +44,9 @@ const environment = { GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, SALT_ROUNDS: process.env.SALT_ROUNDS, - REDIS_URL: process.env.REDIS_URL, - REDIS_PASSWORD: process.env.REDIS_PASSWORD, + REDIS_URL: process.env.REDIS_URL || "localhost:6379", + REDIS_PASSWORD: process.env.REDIS_PASSWORD || "budibase", + MOCK_REDIS: process.env.MOCK_REDIS, MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, AWS_REGION: process.env.AWS_REGION, diff --git a/packages/backend-core/src/queue/queue.ts b/packages/backend-core/src/queue/queue.ts index b34d46e463..8e1fc1fbf3 100644 --- a/packages/backend-core/src/queue/queue.ts +++ b/packages/backend-core/src/queue/queue.ts @@ -4,7 +4,6 @@ import { JobQueue } from "./constants" import InMemoryQueue from "./inMemoryQueue" import BullQueue from "bull" import { addListeners, StalledFn } from "./listeners" -const { opts: redisOpts, redisProtocolUrl } = getRedisOptions() const CLEANUP_PERIOD_MS = 60 * 1000 let QUEUES: BullQueue.Queue[] | InMemoryQueue[] = [] @@ -20,6 +19,7 @@ export function createQueue( jobQueue: JobQueue, opts: { removeStalledCb?: StalledFn } = {} ): BullQueue.Queue { + const { opts: redisOpts, redisProtocolUrl } = getRedisOptions() const queueConfig: any = redisProtocolUrl || { redis: redisOpts } let queue: any if (!env.isTest()) { diff --git a/packages/backend-core/src/redis/redis.ts b/packages/backend-core/src/redis/redis.ts index 0267709cdc..2669cd816a 100644 --- a/packages/backend-core/src/redis/redis.ts +++ b/packages/backend-core/src/redis/redis.ts @@ -1,6 +1,6 @@ import env from "../environment" // ioredis mock is all in memory -const Redis = env.isTest() ? require("ioredis-mock") : require("ioredis") +const Redis = env.MOCK_REDIS ? require("ioredis-mock") : require("ioredis") import { addDbPrefix, removeDbPrefix, @@ -17,8 +17,13 @@ const DEFAULT_SELECT_DB = SelectableDatabase.DEFAULT // for testing just generate the client once let CLOSED = false let CLIENTS: { [key: number]: any } = {} -// if in test always connected -let CONNECTED = env.isTest() + +let CONNECTED = false + +// mock redis always connected +if (env.MOCK_REDIS) { + CONNECTED = true +} function pickClient(selectDb: number): any { return CLIENTS[selectDb] @@ -57,7 +62,7 @@ function init(selectDb = DEFAULT_SELECT_DB) { return } // testing uses a single in memory client - if (env.isTest()) { + if (env.MOCK_REDIS) { CLIENTS[selectDb] = new Redis(getRedisOptions()) } // start the timer - only allowed 5 seconds to connect diff --git a/packages/backend-core/src/redis/utils.ts b/packages/backend-core/src/redis/utils.ts index 4c556ebd54..7606c77b87 100644 --- a/packages/backend-core/src/redis/utils.ts +++ b/packages/backend-core/src/redis/utils.ts @@ -2,8 +2,6 @@ import env from "../environment" const SLOT_REFRESH_MS = 2000 const CONNECT_TIMEOUT_MS = 10000 -const REDIS_URL = !env.REDIS_URL ? "localhost:6379" : env.REDIS_URL -const REDIS_PASSWORD = !env.REDIS_PASSWORD ? "budibase" : env.REDIS_PASSWORD export const SEPARATOR = "-" /** @@ -60,8 +58,8 @@ export enum SelectableDatabase { } export function getRedisOptions(clustered = false) { - let password = REDIS_PASSWORD - let url: string[] | string = REDIS_URL.split("//") + let password = env.REDIS_PASSWORD + let url: string[] | string = env.REDIS_URL.split("//") // get rid of the protocol url = url.length > 1 ? url[1] : url[0] // check for a password etc @@ -78,8 +76,8 @@ export function getRedisOptions(clustered = false) { let redisProtocolUrl // fully qualified redis URL - if (/rediss?:\/\//.test(REDIS_URL)) { - redisProtocolUrl = REDIS_URL + if (/rediss?:\/\//.test(env.REDIS_URL)) { + redisProtocolUrl = env.REDIS_URL } const opts: any = { diff --git a/packages/backend-core/tests/utilities/testContainerUtils.ts b/packages/backend-core/tests/utilities/testContainerUtils.ts index 22198bd496..11c5fca806 100644 --- a/packages/backend-core/tests/utilities/testContainerUtils.ts +++ b/packages/backend-core/tests/utilities/testContainerUtils.ts @@ -34,12 +34,17 @@ function getMinioConfig() { return getContainerInfo("minio-service", 9000) } +function getRedisConfig() { + return getContainerInfo("redis-service", 6379) +} + export function setupEnv(...envs: any[]) { const configs = [ { key: "COUCH_DB_PORT", value: getCouchConfig().port }, { key: "COUCH_DB_URL", value: getCouchConfig().url }, { key: "MINIO_PORT", value: getMinioConfig().port }, { key: "MINIO_URL", value: getMinioConfig().url }, + { key: "REDIS_URL", value: getRedisConfig().url }, ] for (const config of configs.filter(x => !!x.value)) { From f53faff7ad80fd7530a20036cd51d22d5933048d Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 13 Feb 2023 12:27:49 +0000 Subject: [PATCH 010/273] Add LOG_4XX to environment --- packages/backend-core/src/environment.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index d742ca1cc9..9a07695734 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -82,6 +82,7 @@ const environment = { SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD, DEPLOYMENT_ENVIRONMENT: process.env.DEPLOYMENT_ENVIRONMENT || "docker-compose", + LOG_4XX: process.env.LOG_4XX, _set(key: any, value: any) { process.env[key] = value // @ts-ignore From cc7eb64a3bcb6be5429c6f232e39d2161a7a6355 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 13 Feb 2023 14:39:24 +0000 Subject: [PATCH 011/273] Rename LOG_4XX to ENABLE_4XX_HTTP_LOGGING and enable by default --- packages/backend-core/src/environment.ts | 2 +- packages/backend-core/src/middleware/errorHandling.ts | 2 +- packages/backend-core/tests/jestEnv.ts | 1 + packages/server/src/tests/jestEnv.ts | 1 + packages/worker/src/tests/jestEnv.ts | 1 + 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index df44416609..ed7a161160 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -83,7 +83,7 @@ const environment = { SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD, DEPLOYMENT_ENVIRONMENT: process.env.DEPLOYMENT_ENVIRONMENT || "docker-compose", - LOG_4XX: process.env.LOG_4XX, + ENABLE_4XX_HTTP_LOGGING: process.env.ENABLE_4XX_HTTP_LOGGING || true, _set(key: any, value: any) { process.env[key] = value // @ts-ignore diff --git a/packages/backend-core/src/middleware/errorHandling.ts b/packages/backend-core/src/middleware/errorHandling.ts index 1baaa92501..5ac70c33e5 100644 --- a/packages/backend-core/src/middleware/errorHandling.ts +++ b/packages/backend-core/src/middleware/errorHandling.ts @@ -9,7 +9,7 @@ export async function errorHandling(ctx: any, next: any) { const status = err.status || err.statusCode || 500 ctx.status = status - if (status > 499 || env.LOG_4XX) { + if (status > 499 || env.ENABLE_4XX_HTTP_LOGGING) { ctx.log.error(err) } diff --git a/packages/backend-core/tests/jestEnv.ts b/packages/backend-core/tests/jestEnv.ts index 71cf865737..ec8de2942e 100644 --- a/packages/backend-core/tests/jestEnv.ts +++ b/packages/backend-core/tests/jestEnv.ts @@ -3,3 +3,4 @@ process.env.MULTI_TENANCY = "1" process.env.NODE_ENV = "jest" process.env.MOCK_REDIS = "1" process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" +process.env.ENABLE_4XX_HTTP_LOGGING = "0" diff --git a/packages/server/src/tests/jestEnv.ts b/packages/server/src/tests/jestEnv.ts index b1ef038c1b..c567b260b3 100644 --- a/packages/server/src/tests/jestEnv.ts +++ b/packages/server/src/tests/jestEnv.ts @@ -6,4 +6,5 @@ process.env.MULTI_TENANCY = "1" // @ts-ignore process.env.BUDIBASE_DIR = tmpdir("budibase-unittests") process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" +process.env.ENABLE_4XX_HTTP_LOGGING = "0" process.env.MOCK_REDIS = "1" diff --git a/packages/worker/src/tests/jestEnv.ts b/packages/worker/src/tests/jestEnv.ts index 602a505c1b..061897451e 100644 --- a/packages/worker/src/tests/jestEnv.ts +++ b/packages/worker/src/tests/jestEnv.ts @@ -2,6 +2,7 @@ process.env.SELF_HOSTED = "0" process.env.NODE_ENV = "jest" process.env.JWT_SECRET = "test-jwtsecret" process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error" +process.env.ENABLE_4XX_HTTP_LOGGING = "0" process.env.MULTI_TENANCY = "1" process.env.MINIO_URL = "http://localhost" process.env.MINIO_ACCESS_KEY = "test" From 6d60c275211cc37000f5f01fd585af1fdcbeb900 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 13 Feb 2023 16:32:14 +0000 Subject: [PATCH 012/273] add store and api funcs --- .../builder/src/stores/portal/auditLogs.js | 37 ++++++++++++ packages/frontend-core/src/api/auditLogs.js | 58 +++++++++++++++++++ packages/frontend-core/src/api/index.js | 3 + 3 files changed, 98 insertions(+) create mode 100644 packages/builder/src/stores/portal/auditLogs.js create mode 100644 packages/frontend-core/src/api/auditLogs.js diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js new file mode 100644 index 0000000000..9381bea86a --- /dev/null +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -0,0 +1,37 @@ +import { writable, get } from "svelte/store" +import { API } from "api" +import { licensing } from "stores/portal" + +export function createAuditLogsStore() { + const { subscribe, set } = writable({ + logs: [], + }) + + async function search(opts = {}) { + if (get(licensing).auditLogsEnabled) { + const paged = await API.searchAuditLogs(opts) + set({ + ...paged, + ...opts, + }) + return paged + } + } + + async function getEventDefinitions() { + return await API.getEventDefinitions() + } + + async function downloadLogs(opts = {}) { + return await API.downloadLogs(opts) + } + + return { + subscribe, + search, + getEventDefinitions, + downloadLogs, + } +} + +export const environment = createAuditLogsStore() diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js new file mode 100644 index 0000000000..9858a88c0b --- /dev/null +++ b/packages/frontend-core/src/api/auditLogs.js @@ -0,0 +1,58 @@ +const buildOpts = ({ + userIds, + appIds, + startDate, + endDate, + metadataSearch, + event, +}) => { + const opts = {} + + if (startDate && endDate) { + opts.startDate = startDate + opts.endDate = endDate + } + + if (metadataSearch) { + opts.metadataSearch = metadataSearch + } + + if (event) { + opts.event = event + } + + if (userIds) { + opts.userId = userIds + } + + if (appIds) { + opts.appId = appIds + } + + return opts +} + +export const buildAuditLogsEndpoints = API => ({ + /** + * Gets a list of users in the current tenant. + */ + searchAuditLogs: async opts => { + return await API.post({ + url: `/api/auditlogs/search`, + body: buildOpts(opts), + }) + }, + + getEventDefinitions: async () => { + return await API.get({ + url: `/api/auditlogs/definitions`, + }) + }, + + downloadLogs: async opts => { + return await API.post({ + url: `/api/auditlogs/definitions`, + body: buildOpts(opts), + }) + }, +}) diff --git a/packages/frontend-core/src/api/index.js b/packages/frontend-core/src/api/index.js index e2935b416b..f8eee45cb8 100644 --- a/packages/frontend-core/src/api/index.js +++ b/packages/frontend-core/src/api/index.js @@ -28,6 +28,8 @@ import { buildPluginEndpoints } from "./plugins" import { buildBackupsEndpoints } from "./backups" import { buildEnvironmentVariableEndpoints } from "./environmentVariables" import { buildEventEndpoints } from "./events" +import { buildAuditLogsEndpoints } from "./auditLogs" + const defaultAPIClientConfig = { /** * Certain definitions can't change at runtime for client apps, such as the @@ -250,5 +252,6 @@ export const createAPIClient = config => { ...buildBackupsEndpoints(API), ...buildEnvironmentVariableEndpoints(API), ...buildEventEndpoints(API), + ...buildAuditLogsEndpoints(API), } } From 05ceee1cfee2e91e2a6110c8e6d768fbdfbeeb45 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 13 Feb 2023 17:13:59 +0000 Subject: [PATCH 013/273] Moving lucene handling to backend-core so that it can be used for other databases (outside row indexes). --- packages/backend-core/src/db/index.ts | 1 + packages/backend-core/src/db/lucene.ts | 563 ++++++++++++++++++ packages/backend-core/src/index.ts | 2 + .../src/api/controllers/row/internalSearch.ts | 527 +--------------- .../server/src/api/controllers/row/utils.ts | 3 +- packages/server/src/integrations/base/sql.ts | 4 +- .../server/src/integrations/base/utils.ts | 12 - packages/worker/src/api/routes/index.ts | 3 + 8 files changed, 578 insertions(+), 537 deletions(-) create mode 100644 packages/backend-core/src/db/lucene.ts delete mode 100644 packages/server/src/integrations/base/utils.ts diff --git a/packages/backend-core/src/db/index.ts b/packages/backend-core/src/db/index.ts index 0d9f75fa18..a569b17b36 100644 --- a/packages/backend-core/src/db/index.ts +++ b/packages/backend-core/src/db/index.ts @@ -7,3 +7,4 @@ export { default as Replication } from "./Replication" // exports to support old export structure export * from "../constants/db" export { getGlobalDBName, baseGlobalDBName } from "../context" +export * from "./lucene" diff --git a/packages/backend-core/src/db/lucene.ts b/packages/backend-core/src/db/lucene.ts new file mode 100644 index 0000000000..028750797f --- /dev/null +++ b/packages/backend-core/src/db/lucene.ts @@ -0,0 +1,563 @@ +import fetch from "node-fetch" +import { db as dbCore } from "../" +import { SearchFilters, Row } from "@budibase/types" + +const QUERY_START_REGEX = /\d[0-9]*:/g + +export type SearchParams = { + tableId: string + sort?: string + sortOrder?: string + sortType?: string + limit?: number + bookmark?: string + version?: string + rows?: Row[] +} + +export function removeKeyNumbering(key: any): string { + if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) { + const parts = key.split(":") + // remove the number + parts.shift() + return parts.join(":") + } else { + return key + } +} + +/** + * Class to build lucene query URLs. + * Optionally takes a base lucene query object. + */ +export class QueryBuilder { + dbName: string + index: string + query: SearchFilters + limit: number + sort?: string + bookmark?: string + sortOrder: string + sortType: string + includeDocs: boolean + version?: string + + constructor(dbName: string, index: string, base?: SearchFilters) { + this.dbName = dbName + this.index = index + this.query = { + allOr: false, + string: {}, + fuzzy: {}, + range: {}, + equal: {}, + notEqual: {}, + empty: {}, + notEmpty: {}, + oneOf: {}, + contains: {}, + notContains: {}, + containsAny: {}, + ...base, + } + this.limit = 50 + this.sortOrder = "ascending" + this.sortType = "string" + this.includeDocs = true + } + + setVersion(version?: string) { + if (version != null) { + this.version = version + } + return this + } + + setTable(tableId: string) { + this.query.equal!.tableId = tableId + return this + } + + setLimit(limit?: number) { + if (limit != null) { + this.limit = limit + } + return this + } + + setSort(sort?: string) { + if (sort != null) { + this.sort = sort + } + return this + } + + setSortOrder(sortOrder?: string) { + if (sortOrder != null) { + this.sortOrder = sortOrder + } + return this + } + + setSortType(sortType?: string) { + if (sortType != null) { + this.sortType = sortType + } + return this + } + + setBookmark(bookmark?: string) { + if (bookmark != null) { + this.bookmark = bookmark + } + return this + } + + excludeDocs() { + this.includeDocs = false + return this + } + + addString(key: string, partial: string) { + this.query.string![key] = partial + return this + } + + addFuzzy(key: string, fuzzy: string) { + this.query.fuzzy![key] = fuzzy + return this + } + + addRange(key: string, low: string | number, high: string | number) { + this.query.range![key] = { + low, + high, + } + return this + } + + addEqual(key: string, value: any) { + this.query.equal![key] = value + return this + } + + addNotEqual(key: string, value: any) { + this.query.notEqual![key] = value + return this + } + + addEmpty(key: string, value: any) { + this.query.empty![key] = value + return this + } + + addNotEmpty(key: string, value: any) { + this.query.notEmpty![key] = value + return this + } + + addOneOf(key: string, value: any) { + this.query.oneOf![key] = value + return this + } + + addContains(key: string, value: any) { + this.query.contains![key] = value + return this + } + + addNotContains(key: string, value: any) { + this.query.notContains![key] = value + return this + } + + addContainsAny(key: string, value: any) { + this.query.containsAny![key] = value + return this + } + + /** + * Preprocesses a value before going into a lucene search. + * Transforms strings to lowercase and wraps strings and bools in quotes. + * @param value The value to process + * @param options The preprocess options + * @returns {string|*} + */ + preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) { + const hasVersion = !!this.version + // Determine if type needs wrapped + const originalType = typeof value + // Convert to lowercase + if (value && lowercase) { + value = value.toLowerCase ? value.toLowerCase() : value + } + // Escape characters + if (escape && originalType === "string") { + value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") + } + + // Wrap in quotes + if (originalType === "string" && !isNaN(value) && !type) { + value = `"${value}"` + } else if (hasVersion && wrap) { + value = originalType === "number" ? value : `"${value}"` + } + return value + } + + buildSearchQuery() { + const builder = this + let allOr = this.query && this.query.allOr + 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 + } + + 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 + } + return `${key}:${builder.preprocess(value, allPreProcessingOpts)}` + } + + const contains = (key: string, value: any, mode = "AND") => { + if (Array.isArray(value) && value.length === 0) { + return null + } + if (!Array.isArray(value)) { + return `${key}:${value}` + } + let statement = `${builder.preprocess(value[0], { escape: true })}` + for (let i = 1; i < value.length; i++) { + statement += ` ${mode} ${builder.preprocess(value[i], { + escape: true, + })}` + } + return `${key}:(${statement})` + } + + const notContains = (key: string, value: any) => { + // @ts-ignore + const allPrefix = allOr === "" ? "*:* AND" : "" + return allPrefix + "NOT " + contains(key, value) + } + + const containsAny = (key: string, value: any) => { + return contains(key, value, "OR") + } + + const oneOf = (key: string, value: any) => { + if (!Array.isArray(value)) { + if (typeof value === "string") { + value = value.split(",") + } else { + return "" + } + } + let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}` + for (let i = 1; i < value.length; i++) { + orStatement += ` OR ${builder.preprocess( + value[i], + allPreProcessingOpts + )}` + } + return `${key}:(${orStatement})` + } + + 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) + key = builder.preprocess(key.replace(/ /g, "_"), { + escape: true, + }) + const expression = queryFn(key, value) + if (expression == null) { + continue + } + if (query.length > 0) { + query += ` ${allOr ? "OR" : "AND"} ` + } + query += expression + } + } + + // Construct the actual lucene search query string from JSON structure + if (this.query.string) { + build(this.query.string, (key: string, value: any) => { + if (!value) { + return null + } + value = builder.preprocess(value, { + escape: true, + lowercase: true, + type: "string", + }) + return `${key}:${value}*` + }) + } + if (this.query.range) { + build(this.query.range, (key: string, value: any) => { + if (!value) { + return null + } + if (value.low == null || value.low === "") { + return null + } + if (value.high == null || value.high === "") { + return null + } + const low = builder.preprocess(value.low, allPreProcessingOpts) + const high = builder.preprocess(value.high, allPreProcessingOpts) + return `${key}:[${low} TO ${high}]` + }) + } + if (this.query.fuzzy) { + build(this.query.fuzzy, (key: string, value: any) => { + if (!value) { + return null + } + value = builder.preprocess(value, { + escape: true, + lowercase: true, + type: "fuzzy", + }) + return `${key}:${value}~` + }) + } + if (this.query.equal) { + build(this.query.equal, equal) + } + if (this.query.notEqual) { + build(this.query.notEqual, (key: string, value: any) => { + if (!value) { + return null + } + return `!${key}:${builder.preprocess(value, allPreProcessingOpts)}` + }) + } + if (this.query.empty) { + build(this.query.empty, (key: string) => `!${key}:["" TO *]`) + } + if (this.query.notEmpty) { + build(this.query.notEmpty, (key: string) => `${key}:["" TO *]`) + } + if (this.query.oneOf) { + build(this.query.oneOf, oneOf) + } + if (this.query.contains) { + build(this.query.contains, contains) + } + if (this.query.notContains) { + build(this.query.notContains, notContains) + } + if (this.query.containsAny) { + build(this.query.containsAny, containsAny) + } + // make sure table ID is always added as an AND + if (tableId) { + query = `(${query})` + allOr = false + build({ tableId }, equal) + } + return query + } + + buildSearchBody() { + let body: any = { + q: this.buildSearchQuery(), + limit: Math.min(this.limit, 200), + include_docs: this.includeDocs, + } + if (this.bookmark) { + body.bookmark = this.bookmark + } + if (this.sort) { + const order = this.sortOrder === "descending" ? "-" : "" + const type = `<${this.sortType}>` + body.sort = `${order}${this.sort.replace(/ /g, "_")}${type}` + } + return body + } + + async run() { + const { url, cookie } = dbCore.getCouchInfo() + const fullPath = `${url}/${this.dbName}/_design/database/_search/${this.index}` + const body = this.buildSearchBody() + return await runQuery(fullPath, body, cookie) + } +} + +/** + * Executes a lucene search query. + * @param url The query URL + * @param body The request body defining search criteria + * @param cookie The auth cookie for CouchDB + * @returns {Promise<{rows: []}>} + */ +const runQuery = async (url: string, body: any, cookie: string) => { + const response = await fetch(url, { + body: JSON.stringify(body), + method: "POST", + headers: { + Authorization: cookie, + }, + }) + const json = await response.json() + + let output: any = { + rows: [], + } + if (json.rows != null && json.rows.length > 0) { + output.rows = json.rows.map((row: any) => row.doc) + } + if (json.bookmark) { + output.bookmark = json.bookmark + } + return output +} + +/** + * Gets round the fixed limit of 200 results from a query by fetching as many + * pages as required and concatenating the results. This recursively operates + * until enough results have been found. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The number of results to fetch + * bookmark {string|null} Current bookmark in the recursive search + * rows {array|null} Current results in the recursive search + * @returns {Promise<*[]|*>} + */ +async function recursiveSearch( + dbName: string, + index: string, + query: any, + params: any +): Promise { + const bookmark = params.bookmark + const rows = params.rows || [] + if (rows.length >= params.limit) { + return rows + } + let pageSize = 200 + if (rows.length > params.limit - 200) { + pageSize = params.limit - rows.length + } + const page = await new QueryBuilder(dbName, index, query) + .setVersion(params.version) + .setTable(params.tableId) + .setBookmark(bookmark) + .setLimit(pageSize) + .setSort(params.sort) + .setSortOrder(params.sortOrder) + .setSortType(params.sortType) + .run() + if (!page.rows.length) { + return rows + } + if (page.rows.length < 200) { + return [...rows, ...page.rows] + } + const newParams = { + ...params, + bookmark: page.bookmark, + rows: [...rows, ...page.rows], + } + return await recursiveSearch(dbName, index, query, newParams) +} + +/** + * Performs a paginated search. A bookmark will be returned to allow the next + * page to be fetched. There is a max limit off 200 results per page in a + * paginated search. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The desired page size + * bookmark {string} The bookmark to resume from + * @returns {Promise<{hasNextPage: boolean, rows: *[]}>} + */ +export async function paginatedSearch( + dbName: string, + index: string, + query: SearchFilters, + params: SearchParams +) { + let limit = params.limit + if (limit == null || isNaN(limit) || limit < 0) { + limit = 50 + } + limit = Math.min(limit, 200) + const search = new QueryBuilder(dbName, index, query) + .setVersion(params.version) + .setTable(params.tableId) + .setSort(params.sort) + .setSortOrder(params.sortOrder) + .setSortType(params.sortType) + const searchResults = await search + .setBookmark(params.bookmark) + .setLimit(limit) + .run() + + // Try fetching 1 row in the next page to see if another page of results + // exists or not + const nextResults = await search + .setTable(params.tableId) + .setBookmark(searchResults.bookmark) + .setLimit(1) + .run() + + return { + ...searchResults, + hasNextPage: nextResults.rows && nextResults.rows.length > 0, + } +} + +/** + * Performs a full search, fetching multiple pages if required to return the + * desired amount of results. There is a limit of 1000 results to avoid + * heavy performance hits, and to avoid client components breaking from + * handling too much data. + * @param dbName {string} Which database to run a lucene query on + * @param index {string} Which search index to utilise + * @param query {object} The JSON query structure + * @param params {object} The search params including: + * tableId {string} The table ID to search + * sort {string} The sort column + * sortOrder {string} The sort order ("ascending" or "descending") + * sortType {string} Whether to treat sortable values as strings or + * numbers. ("string" or "number") + * limit {number} The desired number of results + * @returns {Promise<{rows: *}>} + */ +export async function fullSearch( + dbName: string, + index: string, + query: SearchFilters, + params: SearchParams +) { + let limit = params.limit + if (limit == null || isNaN(limit) || limit < 0) { + limit = 1000 + } + params.limit = Math.min(limit, 1000) + const rows = await recursiveSearch(dbName, index, query, params) + return { rows } +} diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index b38a53e9e4..aa205e0317 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -25,6 +25,8 @@ export * as utils from "./utils" export * as errors from "./errors" export { default as env } from "./environment" +export { SearchParams } from "./db" + // expose error classes directly export * from "./errors" diff --git a/packages/server/src/api/controllers/row/internalSearch.ts b/packages/server/src/api/controllers/row/internalSearch.ts index 7068aabc5a..a250fe0429 100644 --- a/packages/server/src/api/controllers/row/internalSearch.ts +++ b/packages/server/src/api/controllers/row/internalSearch.ts @@ -1,531 +1,16 @@ 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" +import { db as dbCore, context, SearchParams } from "@budibase/backend-core" +import { SearchFilters } 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. - */ -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: {}, - fuzzy: {}, - range: {}, - equal: {}, - notEqual: {}, - empty: {}, - notEmpty: {}, - oneOf: {}, - contains: {}, - notContains: {}, - containsAny: {}, - ...base, - } - this.limit = 50 - this.sortOrder = "ascending" - this.sortType = "string" - this.includeDocs = true - } - - setVersion(version?: string) { - if (version != null) { - this.version = version - } - return this - } - - setTable(tableId: string) { - this.query.equal!.tableId = tableId - return this - } - - setLimit(limit?: number) { - if (limit != null) { - this.limit = limit - } - return this - } - - setSort(sort?: string) { - if (sort != null) { - this.sort = sort - } - return this - } - - setSortOrder(sortOrder?: string) { - if (sortOrder != null) { - this.sortOrder = sortOrder - } - return this - } - - setSortType(sortType?: string) { - if (sortType != null) { - this.sortType = sortType - } - return this - } - - setBookmark(bookmark?: string) { - if (bookmark != null) { - this.bookmark = bookmark - } - return this - } - - excludeDocs() { - this.includeDocs = false - return this - } - - addString(key: string, partial: string) { - this.query.string![key] = partial - return this - } - - addFuzzy(key: string, fuzzy: string) { - this.query.fuzzy![key] = fuzzy - return this - } - - addRange(key: string, low: string | number, high: string | number) { - this.query.range![key] = { - low, - high, - } - return this - } - - addEqual(key: string, value: any) { - this.query.equal![key] = value - return this - } - - addNotEqual(key: string, value: any) { - this.query.notEqual![key] = value - return this - } - - addEmpty(key: string, value: any) { - this.query.empty![key] = value - return this - } - - addNotEmpty(key: string, value: any) { - this.query.notEmpty![key] = value - return this - } - - addOneOf(key: string, value: any) { - this.query.oneOf![key] = value - return this - } - - addContains(key: string, value: any) { - this.query.contains![key] = value - return this - } - - addNotContains(key: string, value: any) { - this.query.notContains![key] = value - return this - } - - addContainsAny(key: string, value: any) { - this.query.containsAny![key] = value - return this - } - - /** - * Preprocesses a value before going into a lucene search. - * Transforms strings to lowercase and wraps strings and bools in quotes. - * @param value The value to process - * @param options The preprocess options - * @returns {string|*} - */ - preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) { - const hasVersion = !!this.version - // Determine if type needs wrapped - const originalType = typeof value - // Convert to lowercase - if (value && lowercase) { - value = value.toLowerCase ? value.toLowerCase() : value - } - // Escape characters - if (escape && originalType === "string") { - value = `${value}`.replace(/[ #+\-&|!(){}\]^"~*?:\\]/g, "\\$&") - } - - // Wrap in quotes - if (originalType === "string" && !isNaN(value) && !type) { - value = `"${value}"` - } else if (hasVersion && wrap) { - value = originalType === "number" ? value : `"${value}"` - } - return value - } - - buildSearchQuery() { - const builder = this - let allOr = this.query && this.query.allOr - 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 - } - - 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 - } - return `${key}:${builder.preprocess(value, allPreProcessingOpts)}` - } - - const contains = (key: string, value: any, mode = "AND") => { - if (Array.isArray(value) && value.length === 0) { - return null - } - if (!Array.isArray(value)) { - return `${key}:${value}` - } - let statement = `${builder.preprocess(value[0], { escape: true })}` - for (let i = 1; i < value.length; i++) { - statement += ` ${mode} ${builder.preprocess(value[i], { - escape: true, - })}` - } - return `${key}:(${statement})` - } - - const notContains = (key: string, value: any) => { - // @ts-ignore - const allPrefix = allOr === "" ? "*:* AND" : "" - return allPrefix + "NOT " + contains(key, value) - } - - const containsAny = (key: string, value: any) => { - return contains(key, value, "OR") - } - - const oneOf = (key: string, value: any) => { - if (!Array.isArray(value)) { - if (typeof value === "string") { - value = value.split(",") - } else { - return "" - } - } - let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}` - for (let i = 1; i < value.length; i++) { - orStatement += ` OR ${builder.preprocess( - value[i], - allPreProcessingOpts - )}` - } - return `${key}:(${orStatement})` - } - - 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) - key = builder.preprocess(key.replace(/ /g, "_"), { - escape: true, - }) - const expression = queryFn(key, value) - if (expression == null) { - continue - } - if (query.length > 0) { - query += ` ${allOr ? "OR" : "AND"} ` - } - query += expression - } - } - - // Construct the actual lucene search query string from JSON structure - if (this.query.string) { - build(this.query.string, (key: string, value: any) => { - if (!value) { - return null - } - value = builder.preprocess(value, { - escape: true, - lowercase: true, - type: "string", - }) - return `${key}:${value}*` - }) - } - if (this.query.range) { - build(this.query.range, (key: string, value: any) => { - if (!value) { - return null - } - if (value.low == null || value.low === "") { - return null - } - if (value.high == null || value.high === "") { - return null - } - const low = builder.preprocess(value.low, allPreProcessingOpts) - const high = builder.preprocess(value.high, allPreProcessingOpts) - return `${key}:[${low} TO ${high}]` - }) - } - if (this.query.fuzzy) { - build(this.query.fuzzy, (key: string, value: any) => { - if (!value) { - return null - } - value = builder.preprocess(value, { - escape: true, - lowercase: true, - type: "fuzzy", - }) - return `${key}:${value}~` - }) - } - if (this.query.equal) { - build(this.query.equal, equal) - } - if (this.query.notEqual) { - build(this.query.notEqual, (key: string, value: any) => { - if (!value) { - return null - } - return `!${key}:${builder.preprocess(value, allPreProcessingOpts)}` - }) - } - if (this.query.empty) { - build(this.query.empty, (key: string) => `!${key}:["" TO *]`) - } - if (this.query.notEmpty) { - build(this.query.notEmpty, (key: string) => `${key}:["" TO *]`) - } - if (this.query.oneOf) { - build(this.query.oneOf, oneOf) - } - if (this.query.contains) { - build(this.query.contains, contains) - } - if (this.query.notContains) { - build(this.query.notContains, notContains) - } - if (this.query.containsAny) { - build(this.query.containsAny, containsAny) - } - // make sure table ID is always added as an AND - if (tableId) { - query = `(${query})` - allOr = false - build({ tableId }, equal) - } - return query - } - - buildSearchBody() { - let body: any = { - q: this.buildSearchQuery(), - limit: Math.min(this.limit, 200), - include_docs: this.includeDocs, - } - if (this.bookmark) { - body.bookmark = this.bookmark - } - if (this.sort) { - const order = this.sortOrder === "descending" ? "-" : "" - const type = `<${this.sortType}>` - body.sort = `${order}${this.sort.replace(/ /g, "_")}${type}` - } - return body - } - - async run() { - 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) - } -} - -/** - * Executes a lucene search query. - * @param url The query URL - * @param body The request body defining search criteria - * @param cookie The auth cookie for CouchDB - * @returns {Promise<{rows: []}>} - */ -const runQuery = async (url: string, body: any, cookie: string) => { - const response = await fetch(url, { - body: JSON.stringify(body), - method: "POST", - headers: { - Authorization: cookie, - }, - }) - const json = await response.json() - - let output: any = { - rows: [], - } - if (json.rows != null && json.rows.length > 0) { - output.rows = json.rows.map((row: any) => row.doc) - } - if (json.bookmark) { - output.bookmark = json.bookmark - } - return output -} - -/** - * Gets round the fixed limit of 200 results from a query by fetching as many - * pages as required and concatenating the results. This recursively operates - * until enough results have been found. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The number of results to fetch - * bookmark {string|null} Current bookmark in the recursive search - * rows {array|null} Current results in the recursive search - * @returns {Promise<*[]|*>} - */ -async function recursiveSearch(query: any, params: any): Promise { - const bookmark = params.bookmark - const rows = params.rows || [] - if (rows.length >= params.limit) { - return rows - } - let pageSize = 200 - if (rows.length > params.limit - 200) { - pageSize = params.limit - rows.length - } - const page = await new QueryBuilder(query) - .setVersion(params.version) - .setTable(params.tableId) - .setBookmark(bookmark) - .setLimit(pageSize) - .setSort(params.sort) - .setSortOrder(params.sortOrder) - .setSortType(params.sortType) - .run() - if (!page.rows.length) { - return rows - } - if (page.rows.length < 200) { - return [...rows, ...page.rows] - } - const newParams = { - ...params, - bookmark: page.bookmark, - rows: [...rows, ...page.rows], - } - return await recursiveSearch(query, newParams) -} - -/** - * Performs a paginated search. A bookmark will be returned to allow the next - * page to be fetched. There is a max limit off 200 results per page in a - * paginated search. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The desired page size - * bookmark {string} The bookmark to resume from - * @returns {Promise<{hasNextPage: boolean, rows: *[]}>} - */ export async function paginatedSearch( query: SearchFilters, params: SearchParams ) { - let limit = params.limit - if (limit == null || isNaN(limit) || limit < 0) { - limit = 50 - } - limit = Math.min(limit, 200) - const search = new QueryBuilder(query) - .setVersion(params.version) - .setTable(params.tableId) - .setSort(params.sort) - .setSortOrder(params.sortOrder) - .setSortType(params.sortType) - const searchResults = await search - .setBookmark(params.bookmark) - .setLimit(limit) - .run() - - // Try fetching 1 row in the next page to see if another page of results - // exists or not - const nextResults = await search - .setTable(params.tableId) - .setBookmark(searchResults.bookmark) - .setLimit(1) - .run() - - return { - ...searchResults, - hasNextPage: nextResults.rows && nextResults.rows.length > 0, - } + const appId = context.getAppId() + return dbCore.paginatedSearch(appId!, SearchIndexes.ROWS, query, params) } -/** - * Performs a full search, fetching multiple pages if required to return the - * desired amount of results. There is a limit of 1000 results to avoid - * heavy performance hits, and to avoid client components breaking from - * handling too much data. - * @param query {object} The JSON query structure - * @param params {object} The search params including: - * tableId {string} The table ID to search - * sort {string} The sort column - * sortOrder {string} The sort order ("ascending" or "descending") - * sortType {string} Whether to treat sortable values as strings or - * numbers. ("string" or "number") - * limit {number} The desired number of results - * @returns {Promise<{rows: *}>} - */ export async function fullSearch(query: SearchFilters, params: SearchParams) { - let limit = params.limit - if (limit == null || isNaN(limit) || limit < 0) { - limit = 1000 - } - params.limit = Math.min(limit, 1000) - const rows = await recursiveSearch(query, params) - return { rows } + const appId = context.getAppId() + return dbCore.fullSearch(appId!, SearchIndexes.ROWS, query, params) } diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index f0f1075205..82232b7f98 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -3,8 +3,7 @@ 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" +import { Row, Table } from "@budibase/types" const validateJs = require("validate.js") const { cloneDeep } = require("lodash/fp") import { Format } from "../view/exporters" diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e42350091b..557fbbedfd 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -6,11 +6,11 @@ import { SearchFilters, SortDirection, } from "@budibase/types" +import { db as dbCore } from "@budibase/backend-core" import { QueryOptions } from "../../definitions/datasource" import { isIsoDateString, SqlClient } from "../utils" import SqlTableQueryBuilder from "./sqlTable" import environment from "../../environment" -import { removeKeyNumbering } from "./utils" const envLimit = environment.SQL_MAX_ROWS ? parseInt(environment.SQL_MAX_ROWS) @@ -136,7 +136,7 @@ class InternalBuilder { fn: (key: string, value: any) => void ) { for (let [key, value] of Object.entries(structure)) { - const updatedKey = removeKeyNumbering(key) + const updatedKey = dbCore.removeKeyNumbering(key) const isRelationshipField = updatedKey.includes(".") if (!opts.relationship && !isRelationshipField) { fn(`${opts.tableName}.${updatedKey}`, value) diff --git a/packages/server/src/integrations/base/utils.ts b/packages/server/src/integrations/base/utils.ts deleted file mode 100644 index 54efdb91a0..0000000000 --- a/packages/server/src/integrations/base/utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -const QUERY_START_REGEX = /\d[0-9]*:/g - -export function removeKeyNumbering(key: any): string { - if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) { - const parts = key.split(":") - // remove the number - parts.shift() - return parts.join(":") - } else { - return key - } -} diff --git a/packages/worker/src/api/routes/index.ts b/packages/worker/src/api/routes/index.ts index 3aa9422238..c64ad44423 100644 --- a/packages/worker/src/api/routes/index.ts +++ b/packages/worker/src/api/routes/index.ts @@ -18,6 +18,8 @@ import accountRoutes from "./system/accounts" import restoreRoutes from "./system/restore" let userGroupRoutes = api.groups +let auditLogRoutes = api.auditLogs + export const routes: Router[] = [ configRoutes, userRoutes, @@ -32,6 +34,7 @@ export const routes: Router[] = [ selfRoutes, licenseRoutes, userGroupRoutes, + auditLogRoutes, migrationRoutes, accountRoutes, restoreRoutes, From 46e9bf144393b62163984113cb23b9ed87a5aab0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 13 Feb 2023 18:16:13 +0000 Subject: [PATCH 014/273] Some updates to add in the audit log DB. --- packages/backend-core/src/constants/db.ts | 4 ++++ packages/backend-core/src/context/mainContext.ts | 14 ++++++++++++++ packages/types/src/api/web/global/auditLogs.ts | 6 ++++-- packages/types/src/documents/global/auditLogs.ts | 4 ++-- packages/types/src/documents/global/index.ts | 1 + 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/backend-core/src/constants/db.ts b/packages/backend-core/src/constants/db.ts index f7d15b3880..d41098c405 100644 --- a/packages/backend-core/src/constants/db.ts +++ b/packages/backend-core/src/constants/db.ts @@ -68,6 +68,7 @@ export enum DocumentType { MEM_VIEW = "view", USER_FLAG = "flag", AUTOMATION_METADATA = "meta_au", + AUDIT_LOG = "al", } export const StaticDatabases = { @@ -88,6 +89,9 @@ export const StaticDatabases = { install: "install", }, }, + AUDIT_LOGS: { + name: "audit-logs", + }, } export const APP_PREFIX = DocumentType.APP + SEPARATOR diff --git a/packages/backend-core/src/context/mainContext.ts b/packages/backend-core/src/context/mainContext.ts index 9884d25d5a..1f14a20778 100644 --- a/packages/backend-core/src/context/mainContext.ts +++ b/packages/backend-core/src/context/mainContext.ts @@ -30,6 +30,13 @@ export function getGlobalDBName(tenantId?: string) { return baseGlobalDBName(tenantId) } +export function getAuditLogDBName(tenantId?: string) { + if (!tenantId) { + tenantId = getTenantId() + } + return `${tenantId}${SEPARATOR}${StaticDatabases.AUDIT_LOGS.name}` +} + export function baseGlobalDBName(tenantId: string | undefined | null) { let dbName if (!tenantId || tenantId === DEFAULT_TENANT_ID) { @@ -228,6 +235,13 @@ export function getGlobalDB(): Database { return getDB(baseGlobalDBName(context?.tenantId)) } +export function getAuditLogsDB(): Database { + if (!getTenantId()) { + throw new Error("Audit log DB not found") + } + return getDB(getAuditLogDBName()) +} + /** * Gets the app database based on whatever the request * contained, dev or prod. diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 7281d0ca36..443cd79aa1 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -1,7 +1,7 @@ import { Event, AuditedEventFriendlyName } from "../../../sdk" import { PaginationResponse, PaginationRequest } from "../" -export interface DownloadAuditLogsRequest { +export interface AuditLogSearchParams { userId?: string[] appId?: string[] event?: Event[] @@ -10,9 +10,11 @@ export interface DownloadAuditLogsRequest { metadataSearch?: string } +export interface DownloadAuditLogsRequest extends AuditLogSearchParams {} + export interface SearchAuditLogsRequest extends PaginationRequest, - DownloadAuditLogsRequest {} + AuditLogSearchParams {} export interface SearchAuditLogsResponse extends PaginationResponse { data: { diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts index bc07bc88d4..5b23650eec 100644 --- a/packages/types/src/documents/global/auditLogs.ts +++ b/packages/types/src/documents/global/auditLogs.ts @@ -1,8 +1,8 @@ import { Document } from "../document" import { Event } from "../../sdk" -export interface AuditLogDocument extends Document { - appId: string +export interface AuditLogDoc extends Document { + appId?: string event: Event userId: string timestamp: string diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index 11ce7513f2..b728439dd6 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -6,3 +6,4 @@ export * from "./quotas" export * from "./schedule" export * from "./templates" export * from "./environmentVariables" +export * from "./auditLogs" From 1ed4f4b8feea5d2d06b719a97b81d2db9895fa17 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 12:37:32 +0000 Subject: [PATCH 015/273] Update on audit logs, getting the full write flow from events configured. --- packages/backend-core/package.json | 1 + packages/backend-core/src/events/events.ts | 11 +- packages/backend-core/tsconfig.json | 6 +- packages/backend-core/yarn.lock | 118 ++- packages/server/package.json | 1 + .../api/controllers/row/ExternalRequest.ts | 5 +- packages/server/yarn.lock | 812 +++++++++++++++++- .../types/src/documents/global/auditLogs.ts | 2 + scripts/link-dependencies.sh | 4 + 9 files changed, 932 insertions(+), 28 deletions(-) diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 705e4b1114..b51afcb8b1 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -25,6 +25,7 @@ "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/types": "2.3.14-alpha.0", + "@budibase/pro": "2.3.14-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 01928221a0..e54497c0cf 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,6 +1,8 @@ -import { Event } from "@budibase/types" +import { Event, IdentityType } from "@budibase/types" +import { sdk } from "@budibase/pro" import { processors } from "./processors" import identification from "./identification" +import { getAppId } from "../context" import * as backfill from "./backfill" export const publishEvent = async ( @@ -14,6 +16,13 @@ export const publishEvent = async ( const backfilling = await backfill.isBackfillingEvent(event) // no backfill - send the event and exit if (!backfilling) { + // only audit log actual events, don't include backfills + const userId = identity.type === IdentityType.USER ? identity.id : undefined + await sdk.auditLogs.write(event, properties, { + userId, + timestamp, + appId: getAppId(), + }) await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/tsconfig.json b/packages/backend-core/tsconfig.json index e95fb9ab4d..62944d7f2c 100644 --- a/packages/backend-core/tsconfig.json +++ b/packages/backend-core/tsconfig.json @@ -4,11 +4,13 @@ "composite": true, "baseUrl": ".", "paths": { - "@budibase/types": ["../types/src"] + "@budibase/types": ["../types/src"], + "@budibase/pro": ["../../../budibase-pro/packages/pro/src"] } }, "references": [ - { "path": "../types" } + { "path": "../types" }, + { "path": "../../../budibase-pro/packages/pro" } ], "exclude": [ "node_modules", diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index d88b1058f9..93ca39ab35 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -475,6 +475,45 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@budibase/backend-core@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.14-alpha.0.tgz#8d60c93e9861301296907f61e770bdf1881b560c" + integrity sha512-lvRl6o9CCUx1VQ6ftu4FYuTp5mGgvbshNYoeaH0DbWFfhLNbibEHxx+pR+6M1ufhbu/EO6jKEr7DDeNiRBBMTw== + dependencies: + "@budibase/nano" "10.1.1" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.14-alpha.0" + "@shopify/jest-koa-mocks" "5.0.1" + "@techpass/passport-openidconnect" "0.3.2" + aws-cloudfront-sign "2.2.0" + aws-sdk "2.1030.0" + bcrypt "5.0.1" + bcryptjs "2.4.3" + bull "4.10.1" + correlation-id "4.0.0" + dotenv "16.0.1" + emitter-listener "1.1.2" + ioredis "4.28.0" + joi "17.6.0" + jsonwebtoken "9.0.0" + koa-passport "4.1.4" + lodash "4.17.21" + lodash.isarguments "3.1.0" + node-fetch "2.6.7" + passport-google-oauth "2.0.0" + passport-jwt "4.0.0" + passport-local "1.0.0" + passport-oauth2-refresh "^2.1.0" + posthog-node "1.3.0" + pouchdb "7.3.0" + pouchdb-find "7.2.2" + redlock "4.2.0" + sanitize-s3-objectkey "0.0.1" + semver "7.3.7" + tar-fs "2.1.1" + uuid "8.3.2" + zlib "1.0.5" + "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -500,6 +539,25 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" +"@budibase/pro@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.14-alpha.0.tgz#db8ac1d0cacea21240c59458c4143e3e55663a4d" + integrity sha512-RJqXlvZmYrKCLxe7uVnc2KmDwE5OmoUZCA9M6b5Ne7ZHqrhtaNB/4Xlr1ESG79///epEWLv+Fde7mpHPzCvsZw== + dependencies: + "@budibase/backend-core" "2.3.14-alpha.0" + "@budibase/types" "2.3.14-alpha.0" + "@koa/router" "8.0.8" + bull "4.10.1" + joi "17.6.0" + jsonwebtoken "8.5.1" + lru-cache "^7.14.1" + node-fetch "^2.6.1" + +"@budibase/types@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" + integrity sha512-D5qOD7YJhHUrPy81C9OpTlVzsXBmZwbF9WdoxYo/M8JYmhTJfj7Fu5dGTyDpipPQVqknFpTsig5kQqG3r08ZZw== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -826,6 +884,18 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@koa/router@8.0.8": + version "8.0.8" + resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" + integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg== + dependencies: + debug "^4.1.1" + http-errors "^1.7.3" + koa-compose "^4.1.0" + methods "^1.1.2" + path-to-regexp "1.x" + urijs "^1.19.2" + "@mapbox/node-pre-gyp@^1.0.0": version "1.0.9" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" @@ -3145,7 +3215,7 @@ http-cookie-agent@^4.0.2: dependencies: agent-base "^6.0.2" -http-errors@^1.6.3, http-errors@~1.8.0: +http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== @@ -3935,17 +4005,7 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - -jsonwebtoken@^8.2.0: +jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -3961,6 +4021,16 @@ jsonwebtoken@^8.2.0: ms "^2.1.1" semver "^5.6.0" +jsonwebtoken@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -4263,6 +4333,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.14.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" + integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== + ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" @@ -4505,6 +4580,13 @@ node-fetch@2.6.7, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.1: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + node-gyp-build-optional-packages@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" @@ -4837,6 +4919,13 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-to-regexp@1.x: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -6154,6 +6243,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urijs@^1.19.2: + version "1.19.11" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" + integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" diff --git a/packages/server/package.json b/packages/server/package.json index a367f65aed..68ed73beed 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -141,6 +141,7 @@ "@types/pouchdb": "6.4.0", "@types/redis": "4.0.11", "@types/server-destroy": "1.0.1", + "@types/supertest": "^2.0.12", "@types/tar": "6.1.3", "@typescript-eslint/parser": "5.45.0", "apidoc": "0.50.4", diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2faff95595..a1522f6c6d 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -24,8 +24,7 @@ import { breakExternalTableId, isSQL } from "../../../integrations/utils" import { processObjectSync } from "@budibase/string-templates" import { cloneDeep } from "lodash/fp" import { processFormulas, processDates } from "../../../utilities/rowProcessor" -import { context } from "@budibase/backend-core" -import { removeKeyNumbering } from "./utils" +import { db as dbCore } from "@budibase/backend-core" import sdk from "../../../sdk" export interface ManyRelationship { @@ -61,7 +60,7 @@ function buildFilters( let prefix = 1 for (let operator of Object.values(filters)) { for (let field of Object.keys(operator || {})) { - if (removeKeyNumbering(field) === "_id") { + if (dbCore.removeKeyNumbering(field) === "_id") { if (primary) { const parts = breakRowIdField(operator[field]) for (let field of primary) { diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 16c86dd298..7efb1e4672 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adobe/spectrum-css-workflow-icons@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4" + integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w== + "@adobe/spectrum-css-workflow-icons@^1.2.1": version "1.5.3" resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.5.3.tgz#5e31ce842b7626f4b99f9d5cd0b17599d287b0bf" @@ -1317,6 +1322,60 @@ uuid "8.3.2" zlib "1.0.5" +"@budibase/bbui@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-2.3.14-alpha.0.tgz#b27a689e221ff94ebf502b9b3c93a20cd327dab4" + integrity sha512-IGO+AsC5tizGUAl+PQrXac9LdSlLDoenADIbxwTZ4Rcr7insPPvH2Xfq0KRHiJCEp9xcHlpkp5ta8ND1uVp1nw== + dependencies: + "@adobe/spectrum-css-workflow-icons" "1.2.1" + "@budibase/string-templates" "2.3.14-alpha.0" + "@spectrum-css/accordion" "3.0.24" + "@spectrum-css/actionbutton" "1.0.1" + "@spectrum-css/actiongroup" "1.0.1" + "@spectrum-css/avatar" "3.0.2" + "@spectrum-css/button" "3.0.1" + "@spectrum-css/buttongroup" "3.0.2" + "@spectrum-css/checkbox" "3.0.2" + "@spectrum-css/dialog" "3.0.1" + "@spectrum-css/divider" "1.0.3" + "@spectrum-css/dropzone" "3.0.2" + "@spectrum-css/fieldgroup" "3.0.2" + "@spectrum-css/fieldlabel" "3.0.1" + "@spectrum-css/icon" "3.0.1" + "@spectrum-css/illustratedmessage" "3.0.2" + "@spectrum-css/inlinealert" "2.0.1" + "@spectrum-css/inputgroup" "3.0.2" + "@spectrum-css/label" "2.0.10" + "@spectrum-css/link" "3.1.1" + "@spectrum-css/menu" "3.0.1" + "@spectrum-css/modal" "3.0.1" + "@spectrum-css/pagination" "3.0.3" + "@spectrum-css/picker" "1.0.1" + "@spectrum-css/popover" "3.0.1" + "@spectrum-css/progressbar" "1.0.2" + "@spectrum-css/progresscircle" "1.0.2" + "@spectrum-css/radio" "3.0.2" + "@spectrum-css/search" "3.0.2" + "@spectrum-css/sidenav" "3.0.2" + "@spectrum-css/slider" "3.0.1" + "@spectrum-css/statuslight" "3.0.2" + "@spectrum-css/stepper" "3.0.3" + "@spectrum-css/switch" "1.0.2" + "@spectrum-css/table" "3.0.1" + "@spectrum-css/tabs" "3.2.12" + "@spectrum-css/tags" "3.0.2" + "@spectrum-css/textfield" "3.0.1" + "@spectrum-css/toast" "3.0.1" + "@spectrum-css/tooltip" "3.0.3" + "@spectrum-css/treeview" "3.0.2" + "@spectrum-css/typography" "3.0.1" + "@spectrum-css/underlay" "2.0.9" + "@spectrum-css/vars" "3.0.1" + dayjs "^1.10.4" + easymde "^2.16.1" + svelte-flatpickr "^3.2.3" + svelte-portal "^1.0.0" + "@budibase/bbui@^0.9.139": version "0.9.190" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.190.tgz#e1ec400ac90f556bfbc80fc23a04506f1585ea81" @@ -1367,6 +1426,71 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" +"@budibase/client@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-2.3.14-alpha.0.tgz#86fc86e557ab708e160b5c85c8853d11c6ad571f" + integrity sha512-pqPau8P7MG99rilSNh5MjNdNJKSytyr8b83i8vHydAvB++6+ekMwZfRcYrnR2wLXkg6ZztI/CmSkAYU4i1AYtw== + dependencies: + "@budibase/bbui" "2.3.14-alpha.0" + "@budibase/frontend-core" "2.3.14-alpha.0" + "@budibase/string-templates" "2.3.14-alpha.0" + "@spectrum-css/button" "^3.0.3" + "@spectrum-css/card" "^3.0.3" + "@spectrum-css/divider" "^1.0.3" + "@spectrum-css/link" "^3.1.3" + "@spectrum-css/page" "^3.0.1" + "@spectrum-css/tag" "^3.1.4" + "@spectrum-css/typography" "^3.0.2" + "@spectrum-css/vars" "^3.0.1" + apexcharts "^3.22.1" + dayjs "^1.10.5" + downloadjs "1.4.7" + html5-qrcode "^2.2.1" + leaflet "^1.7.1" + regexparam "^1.3.0" + sanitize-html "^2.7.0" + screenfull "^6.0.1" + shortid "^2.2.15" + socket.io-client "^4.5.1" + svelte "^3.49.0" + svelte-apexcharts "^1.0.2" + svelte-flatpickr "^3.1.0" + svelte-spa-router "^3.0.5" + +"@budibase/frontend-core@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-2.3.14-alpha.0.tgz#8c976af3f30feed688f4f36329bd715d5b5825af" + integrity sha512-Jjhy1+oGnyMVoZDnO612Hvvpxe0yBXzvEmhV+o4SN0eMvpZU48NKBU3buG1SvB1D5Y4rCn1FGsCboSTIk9n7rw== + dependencies: + "@budibase/bbui" "2.3.14-alpha.0" + lodash "^4.17.21" + svelte "^3.46.2" + +"@budibase/handlebars-helpers@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" + integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== + dependencies: + array-sort "^1.0.0" + define-property "^2.0.2" + extend-shallow "^3.0.2" + for-in "^1.0.2" + get-object "^0.2.0" + get-value "^3.0.1" + handlebars "^4.7.7" + handlebars-utils "^1.0.6" + has-value "^2.0.2" + helper-md "^0.2.2" + html-tag "^2.0.0" + is-even "^1.0.0" + is-glob "^4.0.1" + kind-of "^6.0.3" + micromatch "^3.1.5" + relative "^3.0.2" + striptags "^3.1.1" + to-gfm-code-block "^0.1.1" + year "^0.2.1" + "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -1424,6 +1548,18 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" +"@budibase/string-templates@2.3.14-alpha.0": + version "2.3.14-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.3.14-alpha.0.tgz#a4c2bf4d328e383929699a5f9c70ed718ef4727b" + integrity sha512-Ekza3NntysyEXyAI6ha/SawkueCnHmMvudW5XtfIS2byLMdph0KqBp03MCW/sdkZ2mdkGi2Nwu/3nowOGSJxNw== + dependencies: + "@budibase/handlebars-helpers" "^0.11.8" + dayjs "^1.10.4" + handlebars "^4.7.6" + handlebars-utils "^1.0.6" + lodash "^4.17.20" + vm2 "^3.9.4" + "@budibase/types@2.3.14-alpha.0": version "2.3.14-alpha.0" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" @@ -2636,26 +2772,51 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== +"@spectrum-css/accordion@3.0.24": + version "3.0.24" + resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74" + integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA== + +"@spectrum-css/actionbutton@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.1.tgz#9c75da37ea6915919fb574c74bd60dacc03b6577" + integrity sha512-AUqtyNabHF451Aj9i3xz82TxS5Z6k1dttA68/1hMeU9kbPCSS4P6Viw3vaRGs9CSspuR8xnnhDgrq+F+zMy2Hw== + "@spectrum-css/actionbutton@^1.0.1": version "1.1.14" resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.14.tgz#4e12eb7f482fb5944c3d97547591964baebeb1d4" integrity sha512-ViBjdWi23J6vIR4t8JTRQ6jY/+KgpZgCALj3otgy495zMNG7jPeN7sKoy6i6JZJcdIRJA4MjOTVvcDOGkYWUZg== +"@spectrum-css/actiongroup@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.1.tgz#b95b86e7af229e90fe1e70399d8d4b547b4bd31c" + integrity sha512-5Q6uMjzv5BFA2TwGASr/jAtJpTWl26fhWvgGY8kOA0RCSij35l+YJg/FPXf6Nnj2qCOl8DkNycjT9YXJ+bhyVA== + "@spectrum-css/actiongroup@^1.0.1": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.26.tgz#181ee059f28b1342389a128c39d20d2e10566aae" integrity sha512-T1IK9a2Gxix9givm+chGvFtZh5oGBZQc/S2UA9F76JZKu45eCkLkvUH6F670XOrBhDGkVfzvN21QnFymSY43ow== -"@spectrum-css/avatar@^3.0.2": +"@spectrum-css/avatar@3.0.2", "@spectrum-css/avatar@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95" integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ== +"@spectrum-css/button@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.1.tgz#6db8c3e851baecd0f1c2d88fef37d49d01c6e643" + integrity sha512-YXrBtjIYisk4Vaxnp0RiE4gdElQX04P2mc4Pi2GlQ27dJKlHmufYcF+kAqGdtiyK5yjdN/vKRcC8y13aA4rusA== + "@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== +"@spectrum-css/buttongroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.2.tgz#fd3387973ca3131609e32112de42a1c0400a48d8" + integrity sha512-Wu7B4GJ/SAeVHz9SUGAkeIH8pLaZh4t+w2ykSKOPQIRuK2jCBoudkEClVxviNVwqekccf5XLFXg9GpYF1a3Uaw== + "@spectrum-css/buttongroup@^3.0.2": version "3.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.10.tgz#897ea04b3ffea389fc7fe5bf67a6d1f3454b774d" @@ -2666,16 +2827,33 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b" integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg== +"@spectrum-css/checkbox@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.2.tgz#53ca2fba0d9faa1fead10e7206eb1f6cdcfd6ddd" + integrity sha512-hPbGcnm7kJvJS4jp/P/bdaZvbyR1eIE9mteuZqcBgdmyp9m/k6+mW5jmsbtqb3Y4mMPWvOJFfz/sIvWJP0F0Zg== + "@spectrum-css/checkbox@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.1.2.tgz#88698969091da9b50de781d25839446084b4a5f4" integrity sha512-vIuknIhRF/Xtq6OHjOtlhYt722FPcTLBb7Y7tY0Ho8VEpynj3JrVLP/1YYp/YIrYMpsTugxPmbCrEkikkdL6Mg== +"@spectrum-css/dialog@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.1.tgz#33aae036282159f6aa998848b8c0828640a9620a" + integrity sha512-hUFbRR6RGT63MNuP7wP+k9KU+uRuICsduMihskh700e+jiQ+Gsv53fBFDlB843FoZYlIXzFQXgtjMUC5a4Qibw== + "@spectrum-css/dialog@^3.0.1": version "3.0.12" resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.12.tgz#fc97e002ca768a3d99dd10cb6a135c2b06052004" integrity sha512-50rbFa+9eUKT+3uYBX7CkmI7SbQ0Z3CAFwjyjai+itYZ8kf/FcHVFwcLjgrry9scUnKhexMs94kkr0gfQpPe8Q== +"@spectrum-css/divider@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385" + integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA== + dependencies: + "@spectrum-css/vars" "^3.0.2" + "@spectrum-css/divider@^1.0.3": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.26.tgz#44b610b1b6c747536fca08b3f09286341e18ab29" @@ -2683,56 +2861,106 @@ dependencies: "@spectrum-css/vars" "^8.0.0" +"@spectrum-css/dropzone@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.2.tgz#34f137851054442b219fed7f32006b93fc5e0bcf" + integrity sha512-BuBBzm5re6lM0AWgd6V+mI5eEGnnmFEtcFiJBEn9jYNEQYgflFhvnERUt89jMX5WmspiecwI2JBWJFrtFsOzug== + "@spectrum-css/dropzone@^3.0.2": version "3.0.24" resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.24.tgz#edefb3ca5a01705a64d0161a599c59199bab6299" integrity sha512-JY60hUZAAuzS+o2xFOKv0o31cc+5/cjLpTyKEy73oGKsdUXEEMiQtW2PQBCuxh7PNyw29wCULeZ1EW1QdNPyxg== +"@spectrum-css/fieldgroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.2.tgz#1c1afd3c444d8650fefac275dc66a7a913933846" + integrity sha512-Vyw0kQJdLW18J6w4H+YAsoLntvkw5rXmW3CH5H3SDTXkBztxtHSSe3e106Nw5MoZxTfHlom6CxbYXYCTjQfqGw== + "@spectrum-css/fieldgroup@^3.0.2": version "3.1.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.1.3.tgz#945123da56534f1ff6118a9defd18b8a883e34a8" integrity sha512-HIbB3jweNviWXcADoYQW3hanww9RTUIsBUhe0YxSMXUXnQJc/7nlyeLoTRMr2eEVSCREfRnMot/8bZloW7ctnA== +"@spectrum-css/fieldlabel@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.1.tgz#39f7c0f25cc2ff402afeff005341b0832f7c588c" + integrity sha512-LMfwrwIq8wEEvxFLobdLvXRwKrp8o9Fty4iJ9aYl2Rj1uXkfRd8qLz9HGZjLEE1OuJgoTBgamYABl7EvoA5PLw== + "@spectrum-css/fieldlabel@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== +"@spectrum-css/icon@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.1.tgz#e300a6fc353c85c6b5d6e7a364408a940c31b177" + integrity sha512-cGFtIrcQ/7tthdkHK1npuEFiCdYVHLqwmLxghUYQw8Tb8KgJaw3OBO1tpjgsUizexNgu26BjVRIbGxNWuBXIHQ== + "@spectrum-css/icon@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.22.tgz#1dd77e2460121951c60c583edb470d0ba52e6822" integrity sha512-ilrPlHDRGzn7kXVVAwUhoSaMfS6sGlb21ix2gn8IRLBAjDOV8BBV1wJJtjGNw+kzCXMhnVnVOekTdht17Oe9bw== +"@spectrum-css/illustratedmessage@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0" + integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA== + "@spectrum-css/illustratedmessage@^3.0.2": version "3.0.17" resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.17.tgz#49cb2549fda97a6812156bfba6ccdd3a18bebd11" integrity sha512-kpDqeq1U+rEjG1XuiXkbGvS71vn6mpFF/hiwCgFJWudVOfypDPQ4KLfYw1ditFSUzMCm5H6U/RqAShAJn8oMWA== +"@spectrum-css/inlinealert@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.1.tgz#7521f88f6c845806403cc7d925773c7414e204a2" + integrity sha512-Xy5RCOwgurqUXuGQCsEDUduDd5408bmEpmFg+feynG7VFUgLFZWBeylSENB/OqjlFtO76PHXNVdHkhDscPIHTA== + "@spectrum-css/inlinealert@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.6.tgz#4c5e923a1f56a96cc1adb30ef1f06ae04f2c6376" integrity sha512-OpvvoWP02wWyCnF4IgG8SOPkXymovkC9cGtgMS1FdDubnG3tJZB/JeKTsRR9C9Vt3WBaOmISRdSKlZ4lC9CFzA== +"@spectrum-css/inputgroup@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.2.tgz#f1b13603832cbd22394f3d898af13203961f8691" + integrity sha512-O0G3Lw9gxsh8gTLQWIAKkN1O8cWhjpEUl+oR1PguIKFni72uNr2ikU9piOwy/r0gJG2Q/TVs6hAshoAAkmsSzw== + "@spectrum-css/inputgroup@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.8.tgz#fc23afc8a73c24d17249c9d2337e8b42085b298b" integrity sha512-cmQWzFp0GU+4IMc8SSeVFdmQDlRUdPelXaQdKUR9mZuO2iYettg37s0lfBCeJyYkUNTagz0zP8O7A0iXfmeE6g== -"@spectrum-css/label@^2.0.10": +"@spectrum-css/label@2.0.10", "@spectrum-css/label@^2.0.10": version "2.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001" integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ== +"@spectrum-css/link@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.1.tgz#cb526a2e10b50ef5a7ae29cca7272e2610d597eb" + integrity sha512-Bi88lRhTY7g6nM/ryW1yY4Cji211ZYNtRxkxbV7n2lPvwMAAQtyx0qVD3ru4kTGj/FFVvmPR3XiOE10K13HSNA== + "@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3": version "3.1.22" resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.22.tgz#1e061d674789c5b3be5b0680f9f6eae3e695e1c1" integrity sha512-Zf8bfy+rtq07l4qoR6chNxefmatLZQZjudIm96v+lsCXBkjVbiMpjkW9oOcNwTqKB08koMONHHhOf1wk2Faqiw== +"@spectrum-css/menu@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.1.tgz#2a376f991acc24e12ec892bb6b9db2650fc41fbe" + integrity sha512-Qjg0+1O0eC89sb/bRFq2AGnQ8XqhVy23TUXHyffNM8qdcMssnlny3QmhzjURCZKvx/Y5UytCpzhedPQqSpQwZg== + "@spectrum-css/menu@^3.0.1": version "3.0.21" resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.21.tgz#d1f7e6e69d30b5e1edd7ed2c86ea4e08dfd670ab" integrity sha512-G5AIUO26O6IAc6HUGZu4AZgyw0QRyLfSbcKlFGu4oJHzP36cQc1S1uCh8Xp4g5d+n6mU62LxNDLSMpVbwnA00A== +"@spectrum-css/modal@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.1.tgz#613a6b83d0330a4d38db41a98090800751c56d8d" + integrity sha512-F7D99F3cjDGT9DM9sogx/p49jrNYT7a1J6TUoqV73wUf+0gP+dTsskBOo9jB8VbUE+POQPjiDLB+SWLp6iBB+w== + "@spectrum-css/modal@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.22.tgz#05593a613e246a7cbef85d08a6945219e1207209" @@ -2745,107 +2973,222 @@ dependencies: "@spectrum-css/vars" "^4.3.1" +"@spectrum-css/pagination@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65" + integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw== + "@spectrum-css/pagination@^3.0.3": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.11.tgz#68d9f34fe8eb36bf922e41b11f49eac62ac2fc41" integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw== +"@spectrum-css/picker@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.1.tgz#98991198576d26bd14160824e7b6f3c278ff930b" + integrity sha512-Rv4/UBOdNW1gs7WVBCJnPD5VFly8MqP++psDX6kcugUIcfJy0GC3acvElotmKRlCDk8Qxks2W2A0jKeSgphTmA== + "@spectrum-css/picker@^1.0.1": version "1.2.9" resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.9.tgz#854cdca407daaf8e1f821777978690f0804b3c08" integrity sha512-HDUDiqHwM84xfbHJWm4wR67Km3NXcDluhDrkVn8uqOEZrm8y4YiW+esL6FzPgzqLdPIHboQjrdpRq4LiDzGjjA== +"@spectrum-css/popover@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.1.tgz#5863c1efc53f98f9aba2de9186666780041303fc" + integrity sha512-LmOSj/yCwQQ9iGmCYnHiJsJR/HfPiGqI1Jl7pkKxBOCxYBMS/5+ans9vfCN2Qnd0eK7WSbfPg72S6mjye7db2Q== + "@spectrum-css/popover@^3.0.1": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.11.tgz#a7450c01bcf1609264b4a9df58821368b9e224d1" integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q== +"@spectrum-css/progressbar@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.2.tgz#b5a59432517f9ae6dad49d9504691bc5ac42b424" + integrity sha512-+jExeBLtVCqo3BqtFq5WCtZ028Dzk+oUnX6y4z6ZamKPqOyOELOtFnhYnyhyRndQOqYwKUTXx9zsaWA/lpJOHw== + "@spectrum-css/progressbar@^1.0.2": version "1.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.30.tgz#1f1e81ab6080fb843831421f736ed2bccc9b18ed" integrity sha512-tUquDN33RQG8gyrWmwPaCu6I2rxRyv5BBGBPii+1sK7L/DTCJrKXe7TAqoxjNEYzdCvTF/HI1NvnSColWNq0Rw== +"@spectrum-css/progresscircle@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c" + integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ== + "@spectrum-css/progresscircle@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.22.tgz#80c8fd2ac4ee6855297d98c60c3b36082020a32a" integrity sha512-EGb+q+7RxbbsrEPFpJ1P4XBQ4s6Ra0okjQCDDTTKTp/sUY2WIT2BjPzwxlZTxVmSXWiiuRyzyuSYUrgBw9UgWg== +"@spectrum-css/radio@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.2.tgz#9c1386894920bbed604e4e174fbbd45d9d762152" + integrity sha512-0TDdzC9omNXnpKHEXNuuGeXdNh4x8jvTKVUqMRLb7vY4hY94hAdt6X01NBqka+jzK35HxGzpDdPADAz62yZLPQ== + "@spectrum-css/radio@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.23.tgz#118a28c407e7b58bec139483d7e23074d840ae77" integrity sha512-x+08GSufmsyrUU4iBOOMRXZrcHxabXMMm/q2vazDJE8CShztvmdjghCxcwtyM74sjiYmXnCW1V3ztr6zaG5xig== +"@spectrum-css/search@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.2.tgz#70e93e321032d40b399498b2324e3b70e050551e" + integrity sha512-3UbT8yZmNOwrZxq+CUmumE+26ZySZ8OoKNM6U20SLMPLgdx6MrRugVE88r3Bl0sJ0RZX/5bU8nausdiHeX+Jlw== + "@spectrum-css/search@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.1.2.tgz#8d43f35f884f7c190e7694c8d26a3f2cfed01ef0" integrity sha512-8cMK1QB07dbReZ/ECyTyoT2dELZ7hK1b3jEDiWSeLBbXcKirR1OI24sZEnewQY/XWFd/62Z1YdNaaA8S6UuXWQ== +"@spectrum-css/sidenav@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.2.tgz#9d70f408d588ee79c69857751010333671f32713" + integrity sha512-YpIdH/F0jEICYmoduGrnkTmxwJq1kfKxEp0wOs+ZkQOsvKMv1an7nyhsfOKCQqcGNfYzJ9mJAk7/u5+vsxHa8g== + "@spectrum-css/sidenav@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.23.tgz#c218560d472e13a3e0d1499b762df1206dcffbfd" integrity sha512-4IFw2/HMQJRzM0M2c5na/HeY7y5vJoGpMFBkXNpQyhW4TRo7N1rGwYQ5dRD3s4OVEWV4/rjfGV0d/qhfwKUTog== +"@spectrum-css/slider@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/slider/-/slider-3.0.1.tgz#5281e6f47eb5a4fd3d1816c138bf66d01d7f2e49" + integrity sha512-DI2dtMRnQuDM1miVzl3SGyR1khUEKnwdXfO5EHDFwkC3yav43F5QogkfjmjFmWWobMVovdJlAuiaaJ/IHejD0Q== + +"@spectrum-css/statuslight@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5" + integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w== + "@spectrum-css/statuslight@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.8.tgz#3b0ea80712573679870a85d469850230e794a0f7" integrity sha512-zMTHs8lk+I7fLdi9waEEbsCmJ1FxeHcjQ0yltWxuRmGk2vl4MQdQIuHIMI63iblqEaiwnJRjXJoKnWlNvndTJQ== +"@spectrum-css/stepper@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.3.tgz#ae89846886431e3edeee060207b8f81540f73a34" + integrity sha512-prAD61ImlOTs9b6PfB3cB08x4lAfxtvnW+RZiTYky0E8GgZdrc/MfCkL5/oqQaIQUtyQv/3Lb7ELAf/0K8QTXw== + "@spectrum-css/stepper@^3.0.3": version "3.0.25" resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.25.tgz#a6e77d501a9671c083b6dd9a37c6a3f224ffc961" integrity sha512-nlAZKY4KCYQ4IFuFj/P0LXPsB4Ze36ziuaa3k3iy3+1pBDD4gDcGmNpNcTG1LENu0Bt87KhSj8Ba2NV3wBSY8w== +"@spectrum-css/switch@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44" + integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ== + "@spectrum-css/switch@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.22.tgz#8f2fe25a52b4511b9cfde7af45f9bd824b9774d7" integrity sha512-/Q8IxnkSQYo+i3G3BObslSvoKgM0Mm1mS7kmssULOtaQPbaRlRsUNQVaHzcNEX33+fiF/9zKSvs7ypgIvbWp+Q== +"@spectrum-css/table@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.1.tgz#753e0e2498082c0c36b9600828516aff3ac338cd" + integrity sha512-XQ+srMTv9hK1H0nctWUtqyzitmvyb5TNR+7mjAmKRdkBRSTQQSipDhenxZp72ekzMtMoSYZVZ77kgo0Iw3Fpug== + "@spectrum-css/table@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf" integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== +"@spectrum-css/tabs@3.2.12": + version "3.2.12" + resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" + integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== + "@spectrum-css/tabs@^3.0.1": version "3.2.16" resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.16.tgz#c3f7800d8d6f7c9930c28cd01354816328bf72b1" integrity sha512-JUcMB/fiDG/KoyrVstlUMacFJUY4OHKqhMRuPtu9ggUXWCRbSkY8he92v6u0HwY3DuhDoOxNTK8d/PLjk/fsbg== +"@spectrum-css/tag@^3.1.4": + version "3.3.15" + resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.3.15.tgz#971184fd8cb977b85a529f808313851863123278" + integrity sha512-pF6Wh61Z7hmAy20twIlpjdDuivYj6UPtWIzK7giyJKr/qcn20BjVN2ChIeFB1N+vBamJdLsuQOewv4AJ3+LZ2Q== + +"@spectrum-css/tags@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.2.tgz#5bf35fb79c97cd9344de485bd4626ad5b9f07757" + integrity sha512-HbvMk+QHvCDD1/ScvSErpKROcpAbXuMD4Hl/Gz/1A1lQ0fJ/CJeCq/MMsL7zjK1nlItU/ySu8r8KIuRF+6F8SQ== + "@spectrum-css/tags@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac" integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw== +"@spectrum-css/textfield@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.1.tgz#e875b8e37817378ad08fc4af7d53026df38911e5" + integrity sha512-MUV5q87CVxbkNdSNoxGrFbgyKc51ft/WWf3aVEoPdPw5yBnXqFe1w1YmAit5zYDOOhhs58sCLAlUcCMlOpkgrA== + "@spectrum-css/textfield@^3.0.1": version "3.2.3" resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.2.3.tgz#52830498fb3b8957f84bb9bf2cafec7edc55e490" integrity sha512-mtxSQe8VZjQ8PHKlUE03dATAjjxp2Y8XfYmWWFBWWZLeqaojSLv9Q8C/ouK5AenhzCaYpJxTotMjAoivwtmUSw== +"@spectrum-css/toast@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.1.tgz#36f62ea05302761e59b9d53e05f6c04423861796" + integrity sha512-jov++S358BrN2tmMfaoYk1N6u9HojgeuQk61keXrK2m3VE5/n94x7Lg3kIPeSWO0odyDfBlMqT9jacbRey3QTg== + "@spectrum-css/toast@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f" integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w== +"@spectrum-css/tooltip@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281" + integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A== + "@spectrum-css/tooltip@^3.0.3": version "3.1.17" resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.1.17.tgz#1f0822c8b69d16d5f940a2b7eb6514d719e6a0fd" integrity sha512-YDuC+Cc6B8DExjL/7fkPnWb8QwlCkjuMHyuttwP/tq/lryWnrdntojgwK5KvgFRjnZ2WfepZVryIt5LOD3tMdg== +"@spectrum-css/treeview@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.2.tgz#d54d8f17290babb1c885f5d9355e225421beb0d2" + integrity sha512-foO7UBJv1JMFaKgDPVt8jBghZSVbqhXR8TaGaxHSnMubv7ygmKkc1AITrWC2STILCn84ju2vchOohMZfW6sYwg== + "@spectrum-css/treeview@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046" integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw== +"@spectrum-css/typography@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.1.tgz#957dafd9b18c314fa37a88b549042ba2175f5b3f" + integrity sha512-XyR68K2rIZX3u4j7HhMLOqLVHDJZcapp3XUqgYMzMWccBFleA0qPxKpfRWqVIA5DzTMSIw0wEcZPYKWFZ2e6dA== + "@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA== +"@spectrum-css/underlay@2.0.9": + version "2.0.9" + resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.9.tgz#fc10f971d1325cc844b727e6260f7217844060e8" + integrity sha512-X86xd0PG4QobmUyXA90BFGnyygaI8kW64dA4ysf4z0cOvUWjNbAAl3a/DB/WRyrnp63Zqv83T/cgNbetagTbWg== + "@spectrum-css/underlay@^2.0.9": version "2.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.30.tgz#401cfd68df945692bd6bbe281fee98889c930dd1" integrity sha512-Ssq/KERbDuJu3PUWPkBv9+ZIbKooke3oncRoYMXeyP/Gcw5bmQSXOvnlddU5DIK4PJR+pPGVZ9CUUFaYZot4YQ== -"@spectrum-css/vars@^3.0.1": +"@spectrum-css/vars@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.1.tgz#561fd69098f896a647242dd8d6108af603bfa31e" + integrity sha512-l4oRcCOqInChYXZN6OQhpe3isk6l4OE6Ys8cgdlsiKp53suNoQxyyd9p/eGRbCjZgH3xQ8nK0t4DHa7QYC0S6w== + +"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw== @@ -3057,6 +3400,13 @@ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== +"@types/codemirror@^5.60.4": + version "5.60.7" + resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.7.tgz#efbb78e5e79f90c6762c2127c02096648e600808" + integrity sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA== + dependencies: + "@types/tern" "*" + "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -3272,6 +3622,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== +"@types/marked@^4.0.7": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" + integrity sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -3547,6 +3902,14 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/superagent@*": + version "4.1.16" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.16.tgz#12c9c16f232f9d89beab91d69368f96ce8e2d881" + integrity sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + "@types/superagent@^4.1.12": version "4.1.15" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.15.tgz#63297de457eba5e2bc502a7609426c4cceab434a" @@ -3555,6 +3918,13 @@ "@types/cookiejar" "*" "@types/node" "*" +"@types/supertest@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.12.tgz#ddb4a0568597c9aadff8dbec5b2e8fddbe8692fc" + integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== + dependencies: + "@types/superagent" "*" + "@types/tar@6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.3.tgz#46a2ce7617950c4852dfd7e9cd41aa8161b9d750" @@ -3563,6 +3933,13 @@ "@types/node" "*" minipass "^3.3.5" +"@types/tern@*": + version "0.23.4" + resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" + integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== + dependencies: + "@types/estree" "*" + "@types/tough-cookie@*", "@types/tough-cookie@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" @@ -4168,7 +4545,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: +argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4215,6 +4592,15 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA== +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -4358,6 +4744,13 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ== + dependencies: + gulp-header "^1.7.1" + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -5288,6 +5681,18 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== +codemirror-spell-checker@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" + integrity sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ== + dependencies: + typo-js "*" + +codemirror@^5.63.1: + version "5.65.11" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.11.tgz#c818edc3274788c008f636520c5490a1f7009b4f" + integrity sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A== + collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -5438,6 +5843,13 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +concat-with-sourcemaps@*: + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + condense-newlines@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f" @@ -5841,6 +6253,13 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -6037,11 +6456,25 @@ doctrine@3.0.0, doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -6049,6 +6482,22 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domhandler@^5.0.1, domhandler@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -6093,6 +6542,11 @@ download@8.0.0: p-event "^2.1.0" pify "^4.0.1" +downloadjs@1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" + integrity sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -6108,6 +6562,17 @@ duplexify@^4.0.0: readable-stream "^3.1.1" stream-shift "^1.0.0" +easymde@^2.16.1: + version "2.18.0" + resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.18.0.tgz#ff1397d07329b1a7b9187d2d0c20766fa16b3b1b" + integrity sha512-IxVVUxNWIoXLeqtBU4BLc+eS/ScYhT1Dcb6yF5Wchoj1iXAV+TIIDWx+NCaZhY7RcSHqDPKllbYq7nwGKILnoA== + dependencies: + "@types/codemirror" "^5.60.4" + "@types/marked" "^4.0.7" + codemirror "^5.63.1" + codemirror-spell-checker "1.1.2" + marked "^4.1.0" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6270,6 +6735,17 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" +engine.io-client@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91" + integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.11.0" + xmlhttprequest-ssl "~2.0.0" + engine.io-parser@~5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" @@ -6299,6 +6775,16 @@ enhanced-resolve@^5.9.3: graceful-fs "^4.2.4" tapable "^2.2.0" +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== + +entities@^4.2.0, entities@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -7479,6 +7965,14 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" +get-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" + integrity sha512-7P6y6k6EzEFmO/XyUyFlXm1YLJy9xeA1x/grNV8276abX5GuwUtYgKFkRFkLixw4hf4Pz9q2vgv/8Ar42R0HuQ== + dependencies: + is-number "^2.0.2" + isobject "^0.2.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -7541,6 +8035,13 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== +get-value@^3.0.0, get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + getopts@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" @@ -7828,7 +8329,24 @@ gtoken@^5.0.4: google-p12-pem "^3.1.3" jws "^4.0.0" -handlebars@^4.7.7: +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +handlebars-utils@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" + integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== + dependencies: + kind-of "^6.0.0" + typeof-article "^0.1.1" + +handlebars@^4.7.6, handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -7922,6 +8440,14 @@ has-value@^1.0.0: has-values "^1.0.0" isobject "^3.0.0" +has-value@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" + integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== + dependencies: + get-value "^3.0.0" + has-values "^2.0.1" + has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" @@ -7935,6 +8461,13 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +has-values@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" + integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== + dependencies: + kind-of "^6.0.2" + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -7947,6 +8480,16 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helper-md@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" + integrity sha512-49TaQzK+Ic7ZVTq4i1UZxRUJEmAilTk8hz7q4I0WNUaTclLR8ArJV5B3A1fe1xF2HtsDTr2gYKLaVTof/Lt84Q== + dependencies: + ent "^2.2.0" + extend-shallow "^2.0.1" + fs-exists-sync "^0.1.0" + remarkable "^1.6.2" + homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -7976,6 +8519,29 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-tag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" + integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== + dependencies: + is-self-closing "^1.0.1" + kind-of "^6.0.0" + +html5-qrcode@^2.2.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.6.tgz#95f572fd79b84cbce0e509da80eda43a394cec3c" + integrity sha512-yuCJUFzm04xGPM2a40XYPptpioV6K5uJA3Ogy0Xi/a7tAYrcD7T4ZCsbg0T1H2qX/143SZfDG1EINnNFh5rH0A== + +htmlparser2@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -8440,6 +9006,13 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-even@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" + integrity sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg== + dependencies: + is-odd "^0.1.2" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -8546,6 +9119,13 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" +is-number@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== + dependencies: + kind-of "^3.0.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -8568,6 +9148,13 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== +is-odd@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" + integrity sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw== + dependencies: + is-number "^3.0.0" + is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -8585,6 +9172,11 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -8608,6 +9200,13 @@ is-retry-allowed@^2.2.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== +is-self-closing@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" + integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== + dependencies: + self-closing-tags "^1.0.1" + is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -8723,6 +9322,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +isobject@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" + integrity sha512-VaWq6XYAsbvM0wf4dyBO7WH9D7GosB7ZZlqrawI9BBiTMINBeCyqSKBa35m870MY3O4aM31pYyZi9DfGrYMJrQ== + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -9917,7 +10521,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== @@ -9931,12 +10535,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0: +kind-of@^5.0.0, kind-of@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -10152,6 +10756,11 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +leaflet@^1.7.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.3.tgz#52ec436954964e2d3d39e0d433da4b2500d74414" + integrity sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ== + left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -10346,6 +10955,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -10451,6 +11065,21 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -10461,7 +11090,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10613,6 +11242,11 @@ markdown-it@^12.2.0: mdurl "^1.0.1" uc.micro "^1.0.5" +marked@^4.1.0: + version "4.2.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" + integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -10708,7 +11342,7 @@ methods@^1.1.1, methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -11011,6 +11645,16 @@ nan@^2.15.0, nan@^2.16.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== +nanoid@^2.1.0: + version "2.1.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" + integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== + +nanoid@^3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" + integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -11689,6 +12333,11 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== +parse-srcset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" + integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q== + parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -12037,6 +12686,15 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== +postcss@^8.3.11: + version "8.4.21" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" + integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -12808,6 +13466,16 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" +regexparam@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" + integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== + +regexparam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" + integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -12856,6 +13524,21 @@ relative-microtime@^2.0.0: resolved "https://registry.yarnpkg.com/relative-microtime/-/relative-microtime-2.0.0.tgz#cceed2af095ecd72ea32011279c79e5fcc7de29b" integrity sha512-l18ha6HEZc+No/uK4GyAnNxgKW7nvEe35IaeN54sShMojtqik2a6GbTyuiezkjpPaqP874Z3lW5ysBo5irz4NA== +relative@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" + integrity sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA== + dependencies: + isobject "^2.0.0" + +remarkable@^1.6.2: + version "1.7.4" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -13151,6 +13834,18 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" +sanitize-html@^2.7.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.9.0.tgz#f4829557b0175df9059d90fe972d5e6facb8565c" + integrity sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg== + dependencies: + deepmerge "^4.2.2" + escape-string-regexp "^4.0.0" + htmlparser2 "^8.0.0" + is-plain-object "^5.0.0" + parse-srcset "^1.0.2" + postcss "^8.3.11" + sanitize-s3-objectkey@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" @@ -13182,6 +13877,11 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" +screenfull@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.2.tgz#3dbe4b8c4f8f49fb8e33caa8f69d0bca730ab238" + integrity sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw== + search-params@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/search-params/-/search-params-3.0.0.tgz#dbc7c243058e5a33ae1e9870be91f5aced4100d8" @@ -13199,6 +13899,11 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" +self-closing-tags@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" + integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -13351,6 +14056,13 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== +shortid@^2.2.15: + version "2.2.16" + resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" + integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== + dependencies: + nanoid "^2.1.0" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -13491,6 +14203,16 @@ socket.io-adapter@~2.4.0: resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== +socket.io-client@^4.5.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.0.tgz#449255d2e0fe429f5ab47ecd3e3b1716b0039c13" + integrity sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.4.0" + socket.io-parser "~4.2.1" + socket.io-parser@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" @@ -13499,6 +14221,14 @@ socket.io-parser@~4.2.0: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" +socket.io-parser@~4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" + integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + socket.io@^4.5.1: version "4.5.2" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac" @@ -13553,6 +14283,11 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -13975,6 +14710,11 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" +striptags@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" + integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== + style-loader@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" @@ -14074,11 +14814,23 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== +svelte-spa-router@^3.0.5: + version "3.3.0" + resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz#2fc0967a49dc361dfe4d38dddad6e662eed5b42c" + integrity sha512-cwRNe7cxD43sCvSfEeaKiNZg3FCizGxeMcf7CPiWRP3jKXjEma3vxyyuDtPOam6nWbVxl9TNM3hlE/i87ZlqcQ== + dependencies: + regexparam "2.0.1" + svelte@3.49.0: version "3.49.0" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== +svelte@^3.46.2, svelte@^3.49.0: + version "3.55.1" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.55.1.tgz#6f93b153e5248039906ce5fe196efdb9e05dfce8" + integrity sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ== + svg.draggable.js@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" @@ -14458,6 +15210,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +to-gfm-code-block@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" + integrity sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg== + to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -14726,6 +15483,13 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typeof-article@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" + integrity sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw== + dependencies: + kind-of "^3.1.0" + typeof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typeof/-/typeof-1.0.0.tgz#9c84403f2323ae5399167275497638ea1d2f2440" @@ -14736,6 +15500,11 @@ typescript@4.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== +typo-js@*: + version "1.2.2" + resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.2.tgz#340484d81fe518e77c81a5a770162b14492f183b" + integrity sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -15086,6 +15855,14 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" +vm2@^3.9.4: + version "3.9.14" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" + integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== + dependencies: + acorn "^8.7.0" + acorn-walk "^8.2.0" + vuvuzela@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" @@ -15441,6 +16218,11 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" +ws@~8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" + integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== + ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" @@ -15509,6 +16291,11 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + xpath.js@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" @@ -15647,6 +16434,11 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +year@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" + integrity sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w== + ylru@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785" diff --git a/packages/types/src/documents/global/auditLogs.ts b/packages/types/src/documents/global/auditLogs.ts index 5b23650eec..7902997b39 100644 --- a/packages/types/src/documents/global/auditLogs.ts +++ b/packages/types/src/documents/global/auditLogs.ts @@ -1,6 +1,8 @@ import { Document } from "../document" import { Event } from "../../sdk" +export const AuditLogSystemUser = "SYSTEM" + export interface AuditLogDoc extends Document { appId?: string event: Event diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index d2a501162b..3a401e1f02 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -53,6 +53,10 @@ if [ -d "../budibase-pro" ]; then echo "Linking pro to server" cd packages/server && yarn link '@budibase/pro' cd - + + echo "Linking pro to backend-core" + cd packages/backend-core && yarn link '@budibase/pro' + cd - fi if [ -d "../account-portal" ]; then From c60b6da0abca77ab0b96a7edcbe52a2cf806135f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 13:49:30 +0000 Subject: [PATCH 016/273] Removing pro from backend-core. --- packages/backend-core/package.json | 1 - packages/backend-core/src/events/events.ts | 21 ++++++++++++++------- packages/backend-core/tsconfig.json | 6 ++---- packages/types/src/sdk/auditLogs.ts | 13 +++++++++++++ packages/types/src/sdk/index.ts | 1 + scripts/link-dependencies.sh | 4 ---- 6 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 packages/types/src/sdk/auditLogs.ts diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index b51afcb8b1..705e4b1114 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -25,7 +25,6 @@ "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", "@budibase/types": "2.3.14-alpha.0", - "@budibase/pro": "2.3.14-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index e54497c0cf..14ef50b69c 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,10 +1,15 @@ -import { Event, IdentityType } from "@budibase/types" -import { sdk } from "@budibase/pro" +import { Event, IdentityType, AuditLogFn } from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" import * as backfill from "./backfill" +let writeAuditLogs: AuditLogFn | undefined + +export const initAuditLogs = (fn: AuditLogFn) => { + writeAuditLogs = fn +} + export const publishEvent = async ( event: Event, properties: any, @@ -18,11 +23,13 @@ export const publishEvent = async ( if (!backfilling) { // only audit log actual events, don't include backfills const userId = identity.type === IdentityType.USER ? identity.id : undefined - await sdk.auditLogs.write(event, properties, { - userId, - timestamp, - appId: getAppId(), - }) + if (writeAuditLogs) { + await writeAuditLogs(event, properties, { + userId, + timestamp, + appId: getAppId(), + }) + } await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/tsconfig.json b/packages/backend-core/tsconfig.json index 62944d7f2c..e95fb9ab4d 100644 --- a/packages/backend-core/tsconfig.json +++ b/packages/backend-core/tsconfig.json @@ -4,13 +4,11 @@ "composite": true, "baseUrl": ".", "paths": { - "@budibase/types": ["../types/src"], - "@budibase/pro": ["../../../budibase-pro/packages/pro/src"] + "@budibase/types": ["../types/src"] } }, "references": [ - { "path": "../types" }, - { "path": "../../../budibase-pro/packages/pro" } + { "path": "../types" } ], "exclude": [ "node_modules", diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts new file mode 100644 index 0000000000..9f8eb3825c --- /dev/null +++ b/packages/types/src/sdk/auditLogs.ts @@ -0,0 +1,13 @@ +import { Event } from "./events" + +export type AuditWriteOpts = { + appId?: string + timestamp?: string | number + userId?: string +} + +export type AuditLogFn = ( + event: Event, + metadata: any, + opts: AuditWriteOpts +) => Promise diff --git a/packages/types/src/sdk/index.ts b/packages/types/src/sdk/index.ts index f8f9d9cb97..1b0fdb193b 100644 --- a/packages/types/src/sdk/index.ts +++ b/packages/types/src/sdk/index.ts @@ -12,3 +12,4 @@ export * from "./db" export * from "./middleware" export * from "./featureFlag" export * from "./environmentVariables" +export * from "./auditLogs" diff --git a/scripts/link-dependencies.sh b/scripts/link-dependencies.sh index 3a401e1f02..d2a501162b 100755 --- a/scripts/link-dependencies.sh +++ b/scripts/link-dependencies.sh @@ -53,10 +53,6 @@ if [ -d "../budibase-pro" ]; then echo "Linking pro to server" cd packages/server && yarn link '@budibase/pro' cd - - - echo "Linking pro to backend-core" - cd packages/backend-core && yarn link '@budibase/pro' - cd - fi if [ -d "../account-portal" ]; then From 6d83ea9becd14a1a9e8372933843dd8dc2683ff8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 18:03:55 +0000 Subject: [PATCH 017/273] Adding in event auditing to server/worker. --- packages/backend-core/src/events/events.ts | 2 +- packages/backend-core/src/events/index.ts | 1 + packages/backend-core/yarn.lock | 118 +-- packages/server/src/app.ts | 5 + packages/server/yarn.lock | 797 +-------------------- packages/worker/src/index.ts | 5 + 6 files changed, 34 insertions(+), 894 deletions(-) diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 14ef50b69c..ba4b0a7448 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -6,7 +6,7 @@ import * as backfill from "./backfill" let writeAuditLogs: AuditLogFn | undefined -export const initAuditLogs = (fn: AuditLogFn) => { +export const configure = (fn: AuditLogFn) => { writeAuditLogs = fn } diff --git a/packages/backend-core/src/events/index.ts b/packages/backend-core/src/events/index.ts index d0d59a5b22..7aa4d06e58 100644 --- a/packages/backend-core/src/events/index.ts +++ b/packages/backend-core/src/events/index.ts @@ -3,6 +3,7 @@ export * as processors from "./processors" export * as analytics from "./analytics" export { default as identification } from "./identification" export * as backfillCache from "./backfill" +export { configure } from "./events" import { processors } from "./processors" diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 93ca39ab35..d88b1058f9 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -475,45 +475,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.14-alpha.0.tgz#8d60c93e9861301296907f61e770bdf1881b560c" - integrity sha512-lvRl6o9CCUx1VQ6ftu4FYuTp5mGgvbshNYoeaH0DbWFfhLNbibEHxx+pR+6M1ufhbu/EO6jKEr7DDeNiRBBMTw== - dependencies: - "@budibase/nano" "10.1.1" - "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.14-alpha.0" - "@shopify/jest-koa-mocks" "5.0.1" - "@techpass/passport-openidconnect" "0.3.2" - aws-cloudfront-sign "2.2.0" - aws-sdk "2.1030.0" - bcrypt "5.0.1" - bcryptjs "2.4.3" - bull "4.10.1" - correlation-id "4.0.0" - dotenv "16.0.1" - emitter-listener "1.1.2" - ioredis "4.28.0" - joi "17.6.0" - jsonwebtoken "9.0.0" - koa-passport "4.1.4" - lodash "4.17.21" - lodash.isarguments "3.1.0" - node-fetch "2.6.7" - passport-google-oauth "2.0.0" - passport-jwt "4.0.0" - passport-local "1.0.0" - passport-oauth2-refresh "^2.1.0" - posthog-node "1.3.0" - pouchdb "7.3.0" - pouchdb-find "7.2.2" - redlock "4.2.0" - sanitize-s3-objectkey "0.0.1" - semver "7.3.7" - tar-fs "2.1.1" - uuid "8.3.2" - zlib "1.0.5" - "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -539,25 +500,6 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.14-alpha.0.tgz#db8ac1d0cacea21240c59458c4143e3e55663a4d" - integrity sha512-RJqXlvZmYrKCLxe7uVnc2KmDwE5OmoUZCA9M6b5Ne7ZHqrhtaNB/4Xlr1ESG79///epEWLv+Fde7mpHPzCvsZw== - dependencies: - "@budibase/backend-core" "2.3.14-alpha.0" - "@budibase/types" "2.3.14-alpha.0" - "@koa/router" "8.0.8" - bull "4.10.1" - joi "17.6.0" - jsonwebtoken "8.5.1" - lru-cache "^7.14.1" - node-fetch "^2.6.1" - -"@budibase/types@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" - integrity sha512-D5qOD7YJhHUrPy81C9OpTlVzsXBmZwbF9WdoxYo/M8JYmhTJfj7Fu5dGTyDpipPQVqknFpTsig5kQqG3r08ZZw== - "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -884,18 +826,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@koa/router@8.0.8": - version "8.0.8" - resolved "https://registry.yarnpkg.com/@koa/router/-/router-8.0.8.tgz#95f32d11373d03d89dcb63fabe9ac6f471095236" - integrity sha512-FnT93N4NUehnXr+juupDmG2yfi0JnWdCmNEuIXpCG4TtG+9xvtrLambBH3RclycopVUOEYAim2lydiNBI7IRVg== - dependencies: - debug "^4.1.1" - http-errors "^1.7.3" - koa-compose "^4.1.0" - methods "^1.1.2" - path-to-regexp "1.x" - urijs "^1.19.2" - "@mapbox/node-pre-gyp@^1.0.0": version "1.0.9" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" @@ -3215,7 +3145,7 @@ http-cookie-agent@^4.0.2: dependencies: agent-base "^6.0.2" -http-errors@^1.6.3, http-errors@^1.7.3, http-errors@~1.8.0: +http-errors@^1.6.3, http-errors@~1.8.0: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== @@ -4005,7 +3935,17 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== -jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: +jsonwebtoken@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + +jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -4021,16 +3961,6 @@ jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: ms "^2.1.1" semver "^5.6.0" -jsonwebtoken@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" - integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== - dependencies: - jws "^3.2.2" - lodash "^4.17.21" - ms "^2.1.1" - semver "^7.3.8" - jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -4333,11 +4263,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.14.1: - version "7.14.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.14.1.tgz#8da8d2f5f59827edb388e63e459ac23d6d408fea" - integrity sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA== - ltgt@2.2.1, ltgt@^2.1.2, ltgt@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" @@ -4580,13 +4505,6 @@ node-fetch@2.6.7, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.1: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - node-gyp-build-optional-packages@5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" @@ -4919,13 +4837,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-to-regexp@1.x: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -6243,11 +6154,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.19.2: - version "1.19.11" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" - integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index be0c63f06a..af67f9c3b3 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -20,11 +20,16 @@ import * as automations from "./automations" import { Thread } from "./threads" import * as redis from "./utilities/redis" import { events, logging, middleware } from "@budibase/backend-core" +import { sdk } from "@budibase/pro" import { initialise as initialiseWebsockets } from "./websocket" import { startup } from "./startup" const Sentry = require("@sentry/node") const destroyable = require("server-destroy") +// configure events to use the pro audit log write +// can't integrate directly into backend-core due to cyclic issues +events.configure(sdk.auditLogs.write) + const app = new Koa() let mbNumber = parseInt(env.HTTP_MB_LIMIT || "10") diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 7efb1e4672..f79b1d80fe 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@adobe/spectrum-css-workflow-icons@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4" - integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w== - "@adobe/spectrum-css-workflow-icons@^1.2.1": version "1.5.3" resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.5.3.tgz#5e31ce842b7626f4b99f9d5cd0b17599d287b0bf" @@ -1322,60 +1317,6 @@ uuid "8.3.2" zlib "1.0.5" -"@budibase/bbui@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-2.3.14-alpha.0.tgz#b27a689e221ff94ebf502b9b3c93a20cd327dab4" - integrity sha512-IGO+AsC5tizGUAl+PQrXac9LdSlLDoenADIbxwTZ4Rcr7insPPvH2Xfq0KRHiJCEp9xcHlpkp5ta8ND1uVp1nw== - dependencies: - "@adobe/spectrum-css-workflow-icons" "1.2.1" - "@budibase/string-templates" "2.3.14-alpha.0" - "@spectrum-css/accordion" "3.0.24" - "@spectrum-css/actionbutton" "1.0.1" - "@spectrum-css/actiongroup" "1.0.1" - "@spectrum-css/avatar" "3.0.2" - "@spectrum-css/button" "3.0.1" - "@spectrum-css/buttongroup" "3.0.2" - "@spectrum-css/checkbox" "3.0.2" - "@spectrum-css/dialog" "3.0.1" - "@spectrum-css/divider" "1.0.3" - "@spectrum-css/dropzone" "3.0.2" - "@spectrum-css/fieldgroup" "3.0.2" - "@spectrum-css/fieldlabel" "3.0.1" - "@spectrum-css/icon" "3.0.1" - "@spectrum-css/illustratedmessage" "3.0.2" - "@spectrum-css/inlinealert" "2.0.1" - "@spectrum-css/inputgroup" "3.0.2" - "@spectrum-css/label" "2.0.10" - "@spectrum-css/link" "3.1.1" - "@spectrum-css/menu" "3.0.1" - "@spectrum-css/modal" "3.0.1" - "@spectrum-css/pagination" "3.0.3" - "@spectrum-css/picker" "1.0.1" - "@spectrum-css/popover" "3.0.1" - "@spectrum-css/progressbar" "1.0.2" - "@spectrum-css/progresscircle" "1.0.2" - "@spectrum-css/radio" "3.0.2" - "@spectrum-css/search" "3.0.2" - "@spectrum-css/sidenav" "3.0.2" - "@spectrum-css/slider" "3.0.1" - "@spectrum-css/statuslight" "3.0.2" - "@spectrum-css/stepper" "3.0.3" - "@spectrum-css/switch" "1.0.2" - "@spectrum-css/table" "3.0.1" - "@spectrum-css/tabs" "3.2.12" - "@spectrum-css/tags" "3.0.2" - "@spectrum-css/textfield" "3.0.1" - "@spectrum-css/toast" "3.0.1" - "@spectrum-css/tooltip" "3.0.3" - "@spectrum-css/treeview" "3.0.2" - "@spectrum-css/typography" "3.0.1" - "@spectrum-css/underlay" "2.0.9" - "@spectrum-css/vars" "3.0.1" - dayjs "^1.10.4" - easymde "^2.16.1" - svelte-flatpickr "^3.2.3" - svelte-portal "^1.0.0" - "@budibase/bbui@^0.9.139": version "0.9.190" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.190.tgz#e1ec400ac90f556bfbc80fc23a04506f1585ea81" @@ -1426,71 +1367,6 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/client@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/client/-/client-2.3.14-alpha.0.tgz#86fc86e557ab708e160b5c85c8853d11c6ad571f" - integrity sha512-pqPau8P7MG99rilSNh5MjNdNJKSytyr8b83i8vHydAvB++6+ekMwZfRcYrnR2wLXkg6ZztI/CmSkAYU4i1AYtw== - dependencies: - "@budibase/bbui" "2.3.14-alpha.0" - "@budibase/frontend-core" "2.3.14-alpha.0" - "@budibase/string-templates" "2.3.14-alpha.0" - "@spectrum-css/button" "^3.0.3" - "@spectrum-css/card" "^3.0.3" - "@spectrum-css/divider" "^1.0.3" - "@spectrum-css/link" "^3.1.3" - "@spectrum-css/page" "^3.0.1" - "@spectrum-css/tag" "^3.1.4" - "@spectrum-css/typography" "^3.0.2" - "@spectrum-css/vars" "^3.0.1" - apexcharts "^3.22.1" - dayjs "^1.10.5" - downloadjs "1.4.7" - html5-qrcode "^2.2.1" - leaflet "^1.7.1" - regexparam "^1.3.0" - sanitize-html "^2.7.0" - screenfull "^6.0.1" - shortid "^2.2.15" - socket.io-client "^4.5.1" - svelte "^3.49.0" - svelte-apexcharts "^1.0.2" - svelte-flatpickr "^3.1.0" - svelte-spa-router "^3.0.5" - -"@budibase/frontend-core@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-2.3.14-alpha.0.tgz#8c976af3f30feed688f4f36329bd715d5b5825af" - integrity sha512-Jjhy1+oGnyMVoZDnO612Hvvpxe0yBXzvEmhV+o4SN0eMvpZU48NKBU3buG1SvB1D5Y4rCn1FGsCboSTIk9n7rw== - dependencies: - "@budibase/bbui" "2.3.14-alpha.0" - lodash "^4.17.21" - svelte "^3.46.2" - -"@budibase/handlebars-helpers@^0.11.8": - version "0.11.8" - resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.8.tgz#6953d29673a8c5c407e096c0a84890465c7ce841" - integrity sha512-ggWJUt0GqsHFAEup5tlWlcrmYML57nKhpNGGLzVsqXVYN8eVmf3xluYmmMe7fDYhQH0leSprrdEXmsdFQF3HAQ== - dependencies: - array-sort "^1.0.0" - define-property "^2.0.2" - extend-shallow "^3.0.2" - for-in "^1.0.2" - get-object "^0.2.0" - get-value "^3.0.1" - handlebars "^4.7.7" - handlebars-utils "^1.0.6" - has-value "^2.0.2" - helper-md "^0.2.2" - html-tag "^2.0.0" - is-even "^1.0.0" - is-glob "^4.0.1" - kind-of "^6.0.3" - micromatch "^3.1.5" - relative "^3.0.2" - striptags "^3.1.1" - to-gfm-code-block "^0.1.1" - year "^0.2.1" - "@budibase/nano@10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" @@ -1548,18 +1424,6 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/string-templates@2.3.14-alpha.0": - version "2.3.14-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-2.3.14-alpha.0.tgz#a4c2bf4d328e383929699a5f9c70ed718ef4727b" - integrity sha512-Ekza3NntysyEXyAI6ha/SawkueCnHmMvudW5XtfIS2byLMdph0KqBp03MCW/sdkZ2mdkGi2Nwu/3nowOGSJxNw== - dependencies: - "@budibase/handlebars-helpers" "^0.11.8" - dayjs "^1.10.4" - handlebars "^4.7.6" - handlebars-utils "^1.0.6" - lodash "^4.17.20" - vm2 "^3.9.4" - "@budibase/types@2.3.14-alpha.0": version "2.3.14-alpha.0" resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.14-alpha.0.tgz#03072a669c016c616278dc01c577119dd710e4fe" @@ -2772,51 +2636,26 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== -"@spectrum-css/accordion@3.0.24": - version "3.0.24" - resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74" - integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA== - -"@spectrum-css/actionbutton@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.1.tgz#9c75da37ea6915919fb574c74bd60dacc03b6577" - integrity sha512-AUqtyNabHF451Aj9i3xz82TxS5Z6k1dttA68/1hMeU9kbPCSS4P6Viw3vaRGs9CSspuR8xnnhDgrq+F+zMy2Hw== - "@spectrum-css/actionbutton@^1.0.1": version "1.1.14" resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.14.tgz#4e12eb7f482fb5944c3d97547591964baebeb1d4" integrity sha512-ViBjdWi23J6vIR4t8JTRQ6jY/+KgpZgCALj3otgy495zMNG7jPeN7sKoy6i6JZJcdIRJA4MjOTVvcDOGkYWUZg== -"@spectrum-css/actiongroup@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.1.tgz#b95b86e7af229e90fe1e70399d8d4b547b4bd31c" - integrity sha512-5Q6uMjzv5BFA2TwGASr/jAtJpTWl26fhWvgGY8kOA0RCSij35l+YJg/FPXf6Nnj2qCOl8DkNycjT9YXJ+bhyVA== - "@spectrum-css/actiongroup@^1.0.1": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/actiongroup/-/actiongroup-1.0.26.tgz#181ee059f28b1342389a128c39d20d2e10566aae" integrity sha512-T1IK9a2Gxix9givm+chGvFtZh5oGBZQc/S2UA9F76JZKu45eCkLkvUH6F670XOrBhDGkVfzvN21QnFymSY43ow== -"@spectrum-css/avatar@3.0.2", "@spectrum-css/avatar@^3.0.2": +"@spectrum-css/avatar@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/avatar/-/avatar-3.0.2.tgz#4f1826223eae330e64b6d3cc899e9bc2e98dac95" integrity sha512-wEczvSqxttTWSiL3cOvXV/RmGRwSkw2w6+slcHhnf0kb7ovymMM+9oz8vvEpEsSeo5u598bc+7ktrKFpAd6soQ== -"@spectrum-css/button@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.1.tgz#6db8c3e851baecd0f1c2d88fef37d49d01c6e643" - integrity sha512-YXrBtjIYisk4Vaxnp0RiE4gdElQX04P2mc4Pi2GlQ27dJKlHmufYcF+kAqGdtiyK5yjdN/vKRcC8y13aA4rusA== - "@spectrum-css/button@^3.0.1", "@spectrum-css/button@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== -"@spectrum-css/buttongroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.2.tgz#fd3387973ca3131609e32112de42a1c0400a48d8" - integrity sha512-Wu7B4GJ/SAeVHz9SUGAkeIH8pLaZh4t+w2ykSKOPQIRuK2jCBoudkEClVxviNVwqekccf5XLFXg9GpYF1a3Uaw== - "@spectrum-css/buttongroup@^3.0.2": version "3.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/buttongroup/-/buttongroup-3.0.10.tgz#897ea04b3ffea389fc7fe5bf67a6d1f3454b774d" @@ -2827,33 +2666,16 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/card/-/card-3.0.3.tgz#56b2e2da6b80c1583228baa279de7407383bfb6b" integrity sha512-+oKLUI2a0QmQP9EzySeq/G4FpUkkdaDNbuEbqCj2IkPMc/2v/nwzsPhh1fj2UIghGAiiUwXfPpzax1e8fyhQUg== -"@spectrum-css/checkbox@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.2.tgz#53ca2fba0d9faa1fead10e7206eb1f6cdcfd6ddd" - integrity sha512-hPbGcnm7kJvJS4jp/P/bdaZvbyR1eIE9mteuZqcBgdmyp9m/k6+mW5jmsbtqb3Y4mMPWvOJFfz/sIvWJP0F0Zg== - "@spectrum-css/checkbox@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.1.2.tgz#88698969091da9b50de781d25839446084b4a5f4" integrity sha512-vIuknIhRF/Xtq6OHjOtlhYt722FPcTLBb7Y7tY0Ho8VEpynj3JrVLP/1YYp/YIrYMpsTugxPmbCrEkikkdL6Mg== -"@spectrum-css/dialog@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.1.tgz#33aae036282159f6aa998848b8c0828640a9620a" - integrity sha512-hUFbRR6RGT63MNuP7wP+k9KU+uRuICsduMihskh700e+jiQ+Gsv53fBFDlB843FoZYlIXzFQXgtjMUC5a4Qibw== - "@spectrum-css/dialog@^3.0.1": version "3.0.12" resolved "https://registry.yarnpkg.com/@spectrum-css/dialog/-/dialog-3.0.12.tgz#fc97e002ca768a3d99dd10cb6a135c2b06052004" integrity sha512-50rbFa+9eUKT+3uYBX7CkmI7SbQ0Z3CAFwjyjai+itYZ8kf/FcHVFwcLjgrry9scUnKhexMs94kkr0gfQpPe8Q== -"@spectrum-css/divider@1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.3.tgz#639e2ebaa0834efa40f42397668bbd5c153ea385" - integrity sha512-Zy4Rn40w8UtzMh3wx/U9+CepSCpm1aOCGftHgWDub0XZuVTzh0c1WwyzTuLCx2Hf21z5VRGNiDh8bGEEzSbtNA== - dependencies: - "@spectrum-css/vars" "^3.0.2" - "@spectrum-css/divider@^1.0.3": version "1.0.26" resolved "https://registry.yarnpkg.com/@spectrum-css/divider/-/divider-1.0.26.tgz#44b610b1b6c747536fca08b3f09286341e18ab29" @@ -2861,106 +2683,56 @@ dependencies: "@spectrum-css/vars" "^8.0.0" -"@spectrum-css/dropzone@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.2.tgz#34f137851054442b219fed7f32006b93fc5e0bcf" - integrity sha512-BuBBzm5re6lM0AWgd6V+mI5eEGnnmFEtcFiJBEn9jYNEQYgflFhvnERUt89jMX5WmspiecwI2JBWJFrtFsOzug== - "@spectrum-css/dropzone@^3.0.2": version "3.0.24" resolved "https://registry.yarnpkg.com/@spectrum-css/dropzone/-/dropzone-3.0.24.tgz#edefb3ca5a01705a64d0161a599c59199bab6299" integrity sha512-JY60hUZAAuzS+o2xFOKv0o31cc+5/cjLpTyKEy73oGKsdUXEEMiQtW2PQBCuxh7PNyw29wCULeZ1EW1QdNPyxg== -"@spectrum-css/fieldgroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.0.2.tgz#1c1afd3c444d8650fefac275dc66a7a913933846" - integrity sha512-Vyw0kQJdLW18J6w4H+YAsoLntvkw5rXmW3CH5H3SDTXkBztxtHSSe3e106Nw5MoZxTfHlom6CxbYXYCTjQfqGw== - "@spectrum-css/fieldgroup@^3.0.2": version "3.1.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldgroup/-/fieldgroup-3.1.3.tgz#945123da56534f1ff6118a9defd18b8a883e34a8" integrity sha512-HIbB3jweNviWXcADoYQW3hanww9RTUIsBUhe0YxSMXUXnQJc/7nlyeLoTRMr2eEVSCREfRnMot/8bZloW7ctnA== -"@spectrum-css/fieldlabel@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.1.tgz#39f7c0f25cc2ff402afeff005341b0832f7c588c" - integrity sha512-LMfwrwIq8wEEvxFLobdLvXRwKrp8o9Fty4iJ9aYl2Rj1uXkfRd8qLz9HGZjLEE1OuJgoTBgamYABl7EvoA5PLw== - "@spectrum-css/fieldlabel@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== -"@spectrum-css/icon@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.1.tgz#e300a6fc353c85c6b5d6e7a364408a940c31b177" - integrity sha512-cGFtIrcQ/7tthdkHK1npuEFiCdYVHLqwmLxghUYQw8Tb8KgJaw3OBO1tpjgsUizexNgu26BjVRIbGxNWuBXIHQ== - "@spectrum-css/icon@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.22.tgz#1dd77e2460121951c60c583edb470d0ba52e6822" integrity sha512-ilrPlHDRGzn7kXVVAwUhoSaMfS6sGlb21ix2gn8IRLBAjDOV8BBV1wJJtjGNw+kzCXMhnVnVOekTdht17Oe9bw== -"@spectrum-css/illustratedmessage@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.2.tgz#6a480be98b027e050b086e7899e40d87adb0a8c0" - integrity sha512-dqnE8X27bGcO0HN8+dYx8O4o0dNNIAqeivOzDHhe2El+V4dTzMrNIerF6G0NLm3GjVf6XliwmitsZK+K6FmbtA== - "@spectrum-css/illustratedmessage@^3.0.2": version "3.0.17" resolved "https://registry.yarnpkg.com/@spectrum-css/illustratedmessage/-/illustratedmessage-3.0.17.tgz#49cb2549fda97a6812156bfba6ccdd3a18bebd11" integrity sha512-kpDqeq1U+rEjG1XuiXkbGvS71vn6mpFF/hiwCgFJWudVOfypDPQ4KLfYw1ditFSUzMCm5H6U/RqAShAJn8oMWA== -"@spectrum-css/inlinealert@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.1.tgz#7521f88f6c845806403cc7d925773c7414e204a2" - integrity sha512-Xy5RCOwgurqUXuGQCsEDUduDd5408bmEpmFg+feynG7VFUgLFZWBeylSENB/OqjlFtO76PHXNVdHkhDscPIHTA== - "@spectrum-css/inlinealert@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@spectrum-css/inlinealert/-/inlinealert-2.0.6.tgz#4c5e923a1f56a96cc1adb30ef1f06ae04f2c6376" integrity sha512-OpvvoWP02wWyCnF4IgG8SOPkXymovkC9cGtgMS1FdDubnG3tJZB/JeKTsRR9C9Vt3WBaOmISRdSKlZ4lC9CFzA== -"@spectrum-css/inputgroup@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.2.tgz#f1b13603832cbd22394f3d898af13203961f8691" - integrity sha512-O0G3Lw9gxsh8gTLQWIAKkN1O8cWhjpEUl+oR1PguIKFni72uNr2ikU9piOwy/r0gJG2Q/TVs6hAshoAAkmsSzw== - "@spectrum-css/inputgroup@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.8.tgz#fc23afc8a73c24d17249c9d2337e8b42085b298b" integrity sha512-cmQWzFp0GU+4IMc8SSeVFdmQDlRUdPelXaQdKUR9mZuO2iYettg37s0lfBCeJyYkUNTagz0zP8O7A0iXfmeE6g== -"@spectrum-css/label@2.0.10", "@spectrum-css/label@^2.0.10": +"@spectrum-css/label@^2.0.10": version "2.0.10" resolved "https://registry.yarnpkg.com/@spectrum-css/label/-/label-2.0.10.tgz#2368651d7636a19385b5d300cdf6272db1916001" integrity sha512-xCbtEiQkZIlLdWFikuw7ifDCC21DOC/KMgVrrVJHXFc4KRQe9LTZSqmGF3tovm+CSq1adE59mYoTbojVQ9YuEQ== -"@spectrum-css/link@3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.1.tgz#cb526a2e10b50ef5a7ae29cca7272e2610d597eb" - integrity sha512-Bi88lRhTY7g6nM/ryW1yY4Cji211ZYNtRxkxbV7n2lPvwMAAQtyx0qVD3ru4kTGj/FFVvmPR3XiOE10K13HSNA== - "@spectrum-css/link@^3.1.1", "@spectrum-css/link@^3.1.3": version "3.1.22" resolved "https://registry.yarnpkg.com/@spectrum-css/link/-/link-3.1.22.tgz#1e061d674789c5b3be5b0680f9f6eae3e695e1c1" integrity sha512-Zf8bfy+rtq07l4qoR6chNxefmatLZQZjudIm96v+lsCXBkjVbiMpjkW9oOcNwTqKB08koMONHHhOf1wk2Faqiw== -"@spectrum-css/menu@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.1.tgz#2a376f991acc24e12ec892bb6b9db2650fc41fbe" - integrity sha512-Qjg0+1O0eC89sb/bRFq2AGnQ8XqhVy23TUXHyffNM8qdcMssnlny3QmhzjURCZKvx/Y5UytCpzhedPQqSpQwZg== - "@spectrum-css/menu@^3.0.1": version "3.0.21" resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.21.tgz#d1f7e6e69d30b5e1edd7ed2c86ea4e08dfd670ab" integrity sha512-G5AIUO26O6IAc6HUGZu4AZgyw0QRyLfSbcKlFGu4oJHzP36cQc1S1uCh8Xp4g5d+n6mU62LxNDLSMpVbwnA00A== -"@spectrum-css/modal@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.1.tgz#613a6b83d0330a4d38db41a98090800751c56d8d" - integrity sha512-F7D99F3cjDGT9DM9sogx/p49jrNYT7a1J6TUoqV73wUf+0gP+dTsskBOo9jB8VbUE+POQPjiDLB+SWLp6iBB+w== - "@spectrum-css/modal@^3.0.1": version "3.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/modal/-/modal-3.0.22.tgz#05593a613e246a7cbef85d08a6945219e1207209" @@ -2973,222 +2745,107 @@ dependencies: "@spectrum-css/vars" "^4.3.1" -"@spectrum-css/pagination@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.3.tgz#b204c3ada384c4af751a354bc428346d82eeea65" - integrity sha512-OJ/v9GeNXJOZ9Yr9LDBYPrR2NCiLOWP9wANT/a5sqFuugRnQbn/HYMnRp9TBxwpDY6ihaPo0T/wi7kLiAJFdDw== - "@spectrum-css/pagination@^3.0.3": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/pagination/-/pagination-3.0.11.tgz#68d9f34fe8eb36bf922e41b11f49eac62ac2fc41" integrity sha512-wjZr7NAcqHK6fxNIGKTYEVtAOJugJTbcz4d8K7DZuUDgBVwLJJHJBi4uJ4KrIRYliMWOvqWTZzCJLmmTfx4cyw== -"@spectrum-css/picker@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.1.tgz#98991198576d26bd14160824e7b6f3c278ff930b" - integrity sha512-Rv4/UBOdNW1gs7WVBCJnPD5VFly8MqP++psDX6kcugUIcfJy0GC3acvElotmKRlCDk8Qxks2W2A0jKeSgphTmA== - "@spectrum-css/picker@^1.0.1": version "1.2.9" resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.2.9.tgz#854cdca407daaf8e1f821777978690f0804b3c08" integrity sha512-HDUDiqHwM84xfbHJWm4wR67Km3NXcDluhDrkVn8uqOEZrm8y4YiW+esL6FzPgzqLdPIHboQjrdpRq4LiDzGjjA== -"@spectrum-css/popover@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.1.tgz#5863c1efc53f98f9aba2de9186666780041303fc" - integrity sha512-LmOSj/yCwQQ9iGmCYnHiJsJR/HfPiGqI1Jl7pkKxBOCxYBMS/5+ans9vfCN2Qnd0eK7WSbfPg72S6mjye7db2Q== - "@spectrum-css/popover@^3.0.1": version "3.0.11" resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.11.tgz#a7450c01bcf1609264b4a9df58821368b9e224d1" integrity sha512-bzyNQJVw6Mn1EBelTaRlXCdd0ZfykNX9O6SHx3a+jXPYu8VBrRpHm0gsfWzPAz1etd1vj1CxwG/teQt4qvyZ/Q== -"@spectrum-css/progressbar@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.2.tgz#b5a59432517f9ae6dad49d9504691bc5ac42b424" - integrity sha512-+jExeBLtVCqo3BqtFq5WCtZ028Dzk+oUnX6y4z6ZamKPqOyOELOtFnhYnyhyRndQOqYwKUTXx9zsaWA/lpJOHw== - "@spectrum-css/progressbar@^1.0.2": version "1.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/progressbar/-/progressbar-1.0.30.tgz#1f1e81ab6080fb843831421f736ed2bccc9b18ed" integrity sha512-tUquDN33RQG8gyrWmwPaCu6I2rxRyv5BBGBPii+1sK7L/DTCJrKXe7TAqoxjNEYzdCvTF/HI1NvnSColWNq0Rw== -"@spectrum-css/progresscircle@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.2.tgz#258ea9170fb70f795edda03e38a61d93bef4487c" - integrity sha512-JLULpyzjIY95lzlWR1yE1gv4l1K6p+scQ+edmuZZUHBzwM3pUtkvHJmUlA9TYdResUYW6Uka60VRdY6lZ8gnFQ== - "@spectrum-css/progresscircle@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/progresscircle/-/progresscircle-1.0.22.tgz#80c8fd2ac4ee6855297d98c60c3b36082020a32a" integrity sha512-EGb+q+7RxbbsrEPFpJ1P4XBQ4s6Ra0okjQCDDTTKTp/sUY2WIT2BjPzwxlZTxVmSXWiiuRyzyuSYUrgBw9UgWg== -"@spectrum-css/radio@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.2.tgz#9c1386894920bbed604e4e174fbbd45d9d762152" - integrity sha512-0TDdzC9omNXnpKHEXNuuGeXdNh4x8jvTKVUqMRLb7vY4hY94hAdt6X01NBqka+jzK35HxGzpDdPADAz62yZLPQ== - "@spectrum-css/radio@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/radio/-/radio-3.0.23.tgz#118a28c407e7b58bec139483d7e23074d840ae77" integrity sha512-x+08GSufmsyrUU4iBOOMRXZrcHxabXMMm/q2vazDJE8CShztvmdjghCxcwtyM74sjiYmXnCW1V3ztr6zaG5xig== -"@spectrum-css/search@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.0.2.tgz#70e93e321032d40b399498b2324e3b70e050551e" - integrity sha512-3UbT8yZmNOwrZxq+CUmumE+26ZySZ8OoKNM6U20SLMPLgdx6MrRugVE88r3Bl0sJ0RZX/5bU8nausdiHeX+Jlw== - "@spectrum-css/search@^3.0.2": version "3.1.2" resolved "https://registry.yarnpkg.com/@spectrum-css/search/-/search-3.1.2.tgz#8d43f35f884f7c190e7694c8d26a3f2cfed01ef0" integrity sha512-8cMK1QB07dbReZ/ECyTyoT2dELZ7hK1b3jEDiWSeLBbXcKirR1OI24sZEnewQY/XWFd/62Z1YdNaaA8S6UuXWQ== -"@spectrum-css/sidenav@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.2.tgz#9d70f408d588ee79c69857751010333671f32713" - integrity sha512-YpIdH/F0jEICYmoduGrnkTmxwJq1kfKxEp0wOs+ZkQOsvKMv1an7nyhsfOKCQqcGNfYzJ9mJAk7/u5+vsxHa8g== - "@spectrum-css/sidenav@^3.0.2": version "3.0.23" resolved "https://registry.yarnpkg.com/@spectrum-css/sidenav/-/sidenav-3.0.23.tgz#c218560d472e13a3e0d1499b762df1206dcffbfd" integrity sha512-4IFw2/HMQJRzM0M2c5na/HeY7y5vJoGpMFBkXNpQyhW4TRo7N1rGwYQ5dRD3s4OVEWV4/rjfGV0d/qhfwKUTog== -"@spectrum-css/slider@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/slider/-/slider-3.0.1.tgz#5281e6f47eb5a4fd3d1816c138bf66d01d7f2e49" - integrity sha512-DI2dtMRnQuDM1miVzl3SGyR1khUEKnwdXfO5EHDFwkC3yav43F5QogkfjmjFmWWobMVovdJlAuiaaJ/IHejD0Q== - -"@spectrum-css/statuslight@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.2.tgz#dc54b6cd113413dcdb909c486b5d7bae60db65c5" - integrity sha512-xodB8g8vGJH20XmUj9ZsPlM1jHrGeRbvmVXkz0q7YvQrYAhim8pP3W+XKKZAletPFAuu8cmUOc6SWn6i4X4z6w== - "@spectrum-css/statuslight@^3.0.2": version "3.0.8" resolved "https://registry.yarnpkg.com/@spectrum-css/statuslight/-/statuslight-3.0.8.tgz#3b0ea80712573679870a85d469850230e794a0f7" integrity sha512-zMTHs8lk+I7fLdi9waEEbsCmJ1FxeHcjQ0yltWxuRmGk2vl4MQdQIuHIMI63iblqEaiwnJRjXJoKnWlNvndTJQ== -"@spectrum-css/stepper@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.3.tgz#ae89846886431e3edeee060207b8f81540f73a34" - integrity sha512-prAD61ImlOTs9b6PfB3cB08x4lAfxtvnW+RZiTYky0E8GgZdrc/MfCkL5/oqQaIQUtyQv/3Lb7ELAf/0K8QTXw== - "@spectrum-css/stepper@^3.0.3": version "3.0.25" resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.25.tgz#a6e77d501a9671c083b6dd9a37c6a3f224ffc961" integrity sha512-nlAZKY4KCYQ4IFuFj/P0LXPsB4Ze36ziuaa3k3iy3+1pBDD4gDcGmNpNcTG1LENu0Bt87KhSj8Ba2NV3wBSY8w== -"@spectrum-css/switch@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.2.tgz#f0b4c69271964573e02b08e90998096e49e1de44" - integrity sha512-zqmHpgWPNg1gEwdUNFYV3CBX5JaeALfIqcJIxE0FLZqr9d1C4+oLE0ItIFzt1bwr4bFAOmkEpvtiY+amluzGxQ== - "@spectrum-css/switch@^1.0.2": version "1.0.22" resolved "https://registry.yarnpkg.com/@spectrum-css/switch/-/switch-1.0.22.tgz#8f2fe25a52b4511b9cfde7af45f9bd824b9774d7" integrity sha512-/Q8IxnkSQYo+i3G3BObslSvoKgM0Mm1mS7kmssULOtaQPbaRlRsUNQVaHzcNEX33+fiF/9zKSvs7ypgIvbWp+Q== -"@spectrum-css/table@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.1.tgz#753e0e2498082c0c36b9600828516aff3ac338cd" - integrity sha512-XQ+srMTv9hK1H0nctWUtqyzitmvyb5TNR+7mjAmKRdkBRSTQQSipDhenxZp72ekzMtMoSYZVZ77kgo0Iw3Fpug== - "@spectrum-css/table@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/table/-/table-3.0.3.tgz#7f7f19905ef3275cbf907ce3a5818e63c30b2caf" integrity sha512-nxwzVjLPsXoY/v4sdxOVYLcC+cEbGgJyLcLclT5LT9MGSbngFeUMJzzVR4EvehzuN4dH7hrATG7Mbuq29Mf0Hg== -"@spectrum-css/tabs@3.2.12": - version "3.2.12" - resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" - integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== - "@spectrum-css/tabs@^3.0.1": version "3.2.16" resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.16.tgz#c3f7800d8d6f7c9930c28cd01354816328bf72b1" integrity sha512-JUcMB/fiDG/KoyrVstlUMacFJUY4OHKqhMRuPtu9ggUXWCRbSkY8he92v6u0HwY3DuhDoOxNTK8d/PLjk/fsbg== -"@spectrum-css/tag@^3.1.4": - version "3.3.15" - resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.3.15.tgz#971184fd8cb977b85a529f808313851863123278" - integrity sha512-pF6Wh61Z7hmAy20twIlpjdDuivYj6UPtWIzK7giyJKr/qcn20BjVN2ChIeFB1N+vBamJdLsuQOewv4AJ3+LZ2Q== - -"@spectrum-css/tags@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.2.tgz#5bf35fb79c97cd9344de485bd4626ad5b9f07757" - integrity sha512-HbvMk+QHvCDD1/ScvSErpKROcpAbXuMD4Hl/Gz/1A1lQ0fJ/CJeCq/MMsL7zjK1nlItU/ySu8r8KIuRF+6F8SQ== - "@spectrum-css/tags@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.3.tgz#fc76d2735cdc442de91b7eb3bee49a928c0767ac" integrity sha512-SL8vPxVDfWcY5VdIuyl0TImEXcOU1I7yCyXkk7MudMwfnYs81FaIyY32hFV9OHj0Tz/36UzRzc7AVMSuRQ53pw== -"@spectrum-css/textfield@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.1.tgz#e875b8e37817378ad08fc4af7d53026df38911e5" - integrity sha512-MUV5q87CVxbkNdSNoxGrFbgyKc51ft/WWf3aVEoPdPw5yBnXqFe1w1YmAit5zYDOOhhs58sCLAlUcCMlOpkgrA== - "@spectrum-css/textfield@^3.0.1": version "3.2.3" resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.2.3.tgz#52830498fb3b8957f84bb9bf2cafec7edc55e490" integrity sha512-mtxSQe8VZjQ8PHKlUE03dATAjjxp2Y8XfYmWWFBWWZLeqaojSLv9Q8C/ouK5AenhzCaYpJxTotMjAoivwtmUSw== -"@spectrum-css/toast@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.1.tgz#36f62ea05302761e59b9d53e05f6c04423861796" - integrity sha512-jov++S358BrN2tmMfaoYk1N6u9HojgeuQk61keXrK2m3VE5/n94x7Lg3kIPeSWO0odyDfBlMqT9jacbRey3QTg== - "@spectrum-css/toast@^3.0.1": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/toast/-/toast-3.0.3.tgz#97c1527384707600832ecda35643ed304615250f" integrity sha512-CjLeaMs+cjUXojCCRtbj0YkD2BoZW16kjj2o5omkEpUTjA34IJ8xJ1a+CCtDILWekhXvN0MBN4sbumcnwcnx8w== -"@spectrum-css/tooltip@3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.0.3.tgz#26b8ca3b3d30e29630244d85eb4fc11d0c841281" - integrity sha512-ztRF7WW1FzyNavXBRc+80z67UoOrY9wl3cMYsVD3MpDnyxdzP8cjza1pCcolKBaFqRTcQKkxKw3GWtGICRKR5A== - "@spectrum-css/tooltip@^3.0.3": version "3.1.17" resolved "https://registry.yarnpkg.com/@spectrum-css/tooltip/-/tooltip-3.1.17.tgz#1f0822c8b69d16d5f940a2b7eb6514d719e6a0fd" integrity sha512-YDuC+Cc6B8DExjL/7fkPnWb8QwlCkjuMHyuttwP/tq/lryWnrdntojgwK5KvgFRjnZ2WfepZVryIt5LOD3tMdg== -"@spectrum-css/treeview@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.2.tgz#d54d8f17290babb1c885f5d9355e225421beb0d2" - integrity sha512-foO7UBJv1JMFaKgDPVt8jBghZSVbqhXR8TaGaxHSnMubv7ygmKkc1AITrWC2STILCn84ju2vchOohMZfW6sYwg== - "@spectrum-css/treeview@^3.0.2": version "3.0.3" resolved "https://registry.yarnpkg.com/@spectrum-css/treeview/-/treeview-3.0.3.tgz#aeda5175158b9f8d7529cb2b394428eb2a428046" integrity sha512-D5gGzZC/KtRArdx86Mesc9+99W9nTbUOeyYGqoJoAfJSOttoT6Tk5CrDvlCmAqjKf5rajemAkGri1ChqvUIwkw== -"@spectrum-css/typography@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.1.tgz#957dafd9b18c314fa37a88b549042ba2175f5b3f" - integrity sha512-XyR68K2rIZX3u4j7HhMLOqLVHDJZcapp3XUqgYMzMWccBFleA0qPxKpfRWqVIA5DzTMSIw0wEcZPYKWFZ2e6dA== - "@spectrum-css/typography@^3.0.1", "@spectrum-css/typography@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/typography/-/typography-3.0.2.tgz#ea3ca0a60e18064527819d48c8c4364cab4fcd38" integrity sha512-5ZOLmQe0edzsDMyhghUd4hBb5uxGsFrxzf+WasfcUw9klSfTsRZ09n1BsaaWbgrLjlMQ+EEHS46v5VNo0Ms2CA== -"@spectrum-css/underlay@2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.9.tgz#fc10f971d1325cc844b727e6260f7217844060e8" - integrity sha512-X86xd0PG4QobmUyXA90BFGnyygaI8kW64dA4ysf4z0cOvUWjNbAAl3a/DB/WRyrnp63Zqv83T/cgNbetagTbWg== - "@spectrum-css/underlay@^2.0.9": version "2.0.30" resolved "https://registry.yarnpkg.com/@spectrum-css/underlay/-/underlay-2.0.30.tgz#401cfd68df945692bd6bbe281fee98889c930dd1" integrity sha512-Ssq/KERbDuJu3PUWPkBv9+ZIbKooke3oncRoYMXeyP/Gcw5bmQSXOvnlddU5DIK4PJR+pPGVZ9CUUFaYZot4YQ== -"@spectrum-css/vars@3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.1.tgz#561fd69098f896a647242dd8d6108af603bfa31e" - integrity sha512-l4oRcCOqInChYXZN6OQhpe3isk6l4OE6Ys8cgdlsiKp53suNoQxyyd9p/eGRbCjZgH3xQ8nK0t4DHa7QYC0S6w== - -"@spectrum-css/vars@^3.0.1", "@spectrum-css/vars@^3.0.2": +"@spectrum-css/vars@^3.0.1": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw== @@ -3400,13 +3057,6 @@ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== -"@types/codemirror@^5.60.4": - version "5.60.7" - resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.7.tgz#efbb78e5e79f90c6762c2127c02096648e600808" - integrity sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA== - dependencies: - "@types/tern" "*" - "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -3622,11 +3272,6 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/marked@^4.0.7": - version "4.0.8" - resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" - integrity sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw== - "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -3933,13 +3578,6 @@ "@types/node" "*" minipass "^3.3.5" -"@types/tern@*": - version "0.23.4" - resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb" - integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg== - dependencies: - "@types/estree" "*" - "@types/tough-cookie@*", "@types/tough-cookie@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" @@ -4545,7 +4183,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.10, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -4592,15 +4230,6 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA== -array-sort@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" - integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== - dependencies: - default-compare "^1.0.0" - get-value "^2.0.6" - kind-of "^5.0.2" - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -4744,13 +4373,6 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== -autolinker@~0.28.0: - version "0.28.1" - resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" - integrity sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ== - dependencies: - gulp-header "^1.7.1" - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -5681,18 +5303,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== -codemirror-spell-checker@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e" - integrity sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ== - dependencies: - typo-js "*" - -codemirror@^5.63.1: - version "5.65.11" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.11.tgz#c818edc3274788c008f636520c5490a1f7009b4f" - integrity sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A== - collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" @@ -5843,13 +5453,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concat-with-sourcemaps@*: - version "1.1.0" - resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" - integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== - dependencies: - source-map "^0.6.1" - condense-newlines@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f" @@ -6253,13 +5856,6 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -default-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" - integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== - dependencies: - kind-of "^5.0.2" - default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -6456,25 +6052,11 @@ doctrine@3.0.0, doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-serializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" - integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - entities "^4.2.0" - dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== -domelementtype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -6482,22 +6064,6 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" -domhandler@^5.0.1, domhandler@^5.0.2: - version "5.0.3" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" - integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== - dependencies: - domelementtype "^2.3.0" - -domutils@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" - integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== - dependencies: - dom-serializer "^2.0.0" - domelementtype "^2.3.0" - domhandler "^5.0.1" - dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -6542,11 +6108,6 @@ download@8.0.0: p-event "^2.1.0" pify "^4.0.1" -downloadjs@1.4.7: - version "1.4.7" - resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" - integrity sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q== - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -6562,17 +6123,6 @@ duplexify@^4.0.0: readable-stream "^3.1.1" stream-shift "^1.0.0" -easymde@^2.16.1: - version "2.18.0" - resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.18.0.tgz#ff1397d07329b1a7b9187d2d0c20766fa16b3b1b" - integrity sha512-IxVVUxNWIoXLeqtBU4BLc+eS/ScYhT1Dcb6yF5Wchoj1iXAV+TIIDWx+NCaZhY7RcSHqDPKllbYq7nwGKILnoA== - dependencies: - "@types/codemirror" "^5.60.4" - "@types/marked" "^4.0.7" - codemirror "^5.63.1" - codemirror-spell-checker "1.1.2" - marked "^4.1.0" - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6735,17 +6285,6 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" -engine.io-client@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.4.0.tgz#88cd3082609ca86d7d3c12f0e746d12db4f47c91" - integrity sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.1" - engine.io-parser "~5.0.3" - ws "~8.11.0" - xmlhttprequest-ssl "~2.0.0" - engine.io-parser@~5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" @@ -6775,16 +6314,6 @@ enhanced-resolve@^5.9.3: graceful-fs "^4.2.4" tapable "^2.2.0" -ent@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== - -entities@^4.2.0, entities@^4.3.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" - integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== - entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -7965,14 +7494,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.3" -get-object@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" - integrity sha512-7P6y6k6EzEFmO/XyUyFlXm1YLJy9xeA1x/grNV8276abX5GuwUtYgKFkRFkLixw4hf4Pz9q2vgv/8Ar42R0HuQ== - dependencies: - is-number "^2.0.2" - isobject "^0.2.0" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -8035,13 +7556,6 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== -get-value@^3.0.0, get-value@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" - integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== - dependencies: - isobject "^3.0.1" - getopts@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4" @@ -8329,24 +7843,7 @@ gtoken@^5.0.4: google-p12-pem "^3.1.3" jws "^4.0.0" -gulp-header@^1.7.1: - version "1.8.12" - resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" - integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== - dependencies: - concat-with-sourcemaps "*" - lodash.template "^4.4.0" - through2 "^2.0.0" - -handlebars-utils@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" - integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== - dependencies: - kind-of "^6.0.0" - typeof-article "^0.1.1" - -handlebars@^4.7.6, handlebars@^4.7.7: +handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -8440,14 +7937,6 @@ has-value@^1.0.0: has-values "^1.0.0" isobject "^3.0.0" -has-value@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" - integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== - dependencies: - get-value "^3.0.0" - has-values "^2.0.1" - has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" @@ -8461,13 +7950,6 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has-values@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" - integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== - dependencies: - kind-of "^6.0.2" - has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -8480,16 +7962,6 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -helper-md@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" - integrity sha512-49TaQzK+Ic7ZVTq4i1UZxRUJEmAilTk8hz7q4I0WNUaTclLR8ArJV5B3A1fe1xF2HtsDTr2gYKLaVTof/Lt84Q== - dependencies: - ent "^2.2.0" - extend-shallow "^2.0.1" - fs-exists-sync "^0.1.0" - remarkable "^1.6.2" - homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -8519,29 +7991,6 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html-tag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" - integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== - dependencies: - is-self-closing "^1.0.1" - kind-of "^6.0.0" - -html5-qrcode@^2.2.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/html5-qrcode/-/html5-qrcode-2.3.6.tgz#95f572fd79b84cbce0e509da80eda43a394cec3c" - integrity sha512-yuCJUFzm04xGPM2a40XYPptpioV6K5uJA3Ogy0Xi/a7tAYrcD7T4ZCsbg0T1H2qX/143SZfDG1EINnNFh5rH0A== - -htmlparser2@^8.0.0: - version "8.0.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" - integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== - dependencies: - domelementtype "^2.3.0" - domhandler "^5.0.2" - domutils "^3.0.1" - entities "^4.3.0" - http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -9006,13 +8455,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-even@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" - integrity sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg== - dependencies: - is-odd "^0.1.2" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -9119,13 +8561,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg== - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -9148,13 +8583,6 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== -is-odd@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" - integrity sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw== - dependencies: - is-number "^3.0.0" - is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -9172,11 +8600,6 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -9200,13 +8623,6 @@ is-retry-allowed@^2.2.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== -is-self-closing@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" - integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== - dependencies: - self-closing-tags "^1.0.1" - is-shared-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" @@ -9322,11 +8738,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" - integrity sha512-VaWq6XYAsbvM0wf4dyBO7WH9D7GosB7ZZlqrawI9BBiTMINBeCyqSKBa35m870MY3O4aM31pYyZi9DfGrYMJrQ== - isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -10521,7 +9932,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== @@ -10535,12 +9946,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0, kind-of@^5.0.2: +kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -10756,11 +10167,6 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" -leaflet@^1.7.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.3.tgz#52ec436954964e2d3d39e0d433da4b2500d74414" - integrity sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ== - left-pad@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" @@ -10955,11 +10361,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== - lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -11065,21 +10466,6 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash.template@^4.4.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -11090,7 +10476,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha512-sVN2zimthq7aZ5sPGXnSz32rZPuqcparVW50chJQe+mzTYV+IsxSsl/2gnkWWE2Of7K3myBQBqtLKOUEHJKRsQ== -lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -11242,11 +10628,6 @@ markdown-it@^12.2.0: mdurl "^1.0.1" uc.micro "^1.0.5" -marked@^4.1.0: - version "4.2.12" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" - integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== - matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -11342,7 +10723,7 @@ methods@^1.1.1, methods@^1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5: +micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -11645,16 +11026,6 @@ nan@^2.15.0, nan@^2.16.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== -nanoid@^2.1.0: - version "2.1.11" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" - integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== - -nanoid@^3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -12333,11 +11704,6 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== -parse-srcset@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1" - integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q== - parse5@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" @@ -12686,15 +12052,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== -postcss@^8.3.11: - version "8.4.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" - integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== - dependencies: - nanoid "^3.3.4" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -13466,16 +12823,6 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexparam@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.1.tgz#c912f5dae371e3798100b3c9ce22b7414d0889fa" - integrity sha512-zRgSaYemnNYxUv+/5SeoHI0eJIgTL/A2pUtXUPLHQxUldagouJ9p+K6IbIZ/JiQuCEv2E2B1O11SjVQy3aMCkw== - -regexparam@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" - integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== - regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -13524,21 +12871,6 @@ relative-microtime@^2.0.0: resolved "https://registry.yarnpkg.com/relative-microtime/-/relative-microtime-2.0.0.tgz#cceed2af095ecd72ea32011279c79e5fcc7de29b" integrity sha512-l18ha6HEZc+No/uK4GyAnNxgKW7nvEe35IaeN54sShMojtqik2a6GbTyuiezkjpPaqP874Z3lW5ysBo5irz4NA== -relative@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" - integrity sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA== - dependencies: - isobject "^2.0.0" - -remarkable@^1.6.2: - version "1.7.4" - resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" - integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== - dependencies: - argparse "^1.0.10" - autolinker "~0.28.0" - remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -13834,18 +13166,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sanitize-html@^2.7.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.9.0.tgz#f4829557b0175df9059d90fe972d5e6facb8565c" - integrity sha512-KY1hpSbqFNcpoLf+nP7iStbP5JfQZ2Nd19ZEE7qFsQqRdp+sO5yX/e5+HoG9puFAcSTEpzQuihfKUltDcLlQjg== - dependencies: - deepmerge "^4.2.2" - escape-string-regexp "^4.0.0" - htmlparser2 "^8.0.0" - is-plain-object "^5.0.0" - parse-srcset "^1.0.2" - postcss "^8.3.11" - sanitize-s3-objectkey@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" @@ -13877,11 +13197,6 @@ schema-utils@^3.1.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -screenfull@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-6.0.2.tgz#3dbe4b8c4f8f49fb8e33caa8f69d0bca730ab238" - integrity sha512-AQdy8s4WhNvUZ6P8F6PB21tSPIYKniic+Ogx0AacBMjKP1GUHN2E9URxQHtCusiwxudnCKkdy4GrHXPPJSkCCw== - search-params@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/search-params/-/search-params-3.0.0.tgz#dbc7c243058e5a33ae1e9870be91f5aced4100d8" @@ -13899,11 +13214,6 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" -self-closing-tags@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" - integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -14056,13 +13366,6 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== -shortid@^2.2.15: - version "2.2.16" - resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" - integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== - dependencies: - nanoid "^2.1.0" - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -14203,16 +13506,6 @@ socket.io-adapter@~2.4.0: resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== -socket.io-client@^4.5.1: - version "4.6.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.6.0.tgz#449255d2e0fe429f5ab47ecd3e3b1716b0039c13" - integrity sha512-2XOp18xnGghUICSd5ziUIS4rB0dhr6S8OvAps8y+HhOjFQlqGcf+FIh6fCIsKKZyWFxJeFPrZRNPGsHDTsz1Ug== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.2" - engine.io-client "~6.4.0" - socket.io-parser "~4.2.1" - socket.io-parser@~4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5" @@ -14221,14 +13514,6 @@ socket.io-parser@~4.2.0: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io-parser@~4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.2.tgz#1dd384019e25b7a3d374877f492ab34f2ad0d206" - integrity sha512-DJtziuKypFkMMHCm2uIshOYC7QaylbtzQwiMYDuCKy3OPkjLzu4B2vAhTlqipRHHzrI0NJeBAizTK7X+6m1jVw== - dependencies: - "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.1" - socket.io@^4.5.1: version "4.5.2" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac" @@ -14283,11 +13568,6 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -14710,11 +13990,6 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" -striptags@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" - integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== - style-loader@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" @@ -14814,23 +14089,11 @@ svelte-portal@^1.0.0: resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== -svelte-spa-router@^3.0.5: - version "3.3.0" - resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.3.0.tgz#2fc0967a49dc361dfe4d38dddad6e662eed5b42c" - integrity sha512-cwRNe7cxD43sCvSfEeaKiNZg3FCizGxeMcf7CPiWRP3jKXjEma3vxyyuDtPOam6nWbVxl9TNM3hlE/i87ZlqcQ== - dependencies: - regexparam "2.0.1" - svelte@3.49.0: version "3.49.0" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== -svelte@^3.46.2, svelte@^3.49.0: - version "3.55.1" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.55.1.tgz#6f93b153e5248039906ce5fe196efdb9e05dfce8" - integrity sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ== - svg.draggable.js@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" @@ -15210,11 +14473,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= -to-gfm-code-block@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" - integrity sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg== - to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -15483,13 +14741,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typeof-article@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" - integrity sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw== - dependencies: - kind-of "^3.1.0" - typeof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typeof/-/typeof-1.0.0.tgz#9c84403f2323ae5399167275497638ea1d2f2440" @@ -15500,11 +14751,6 @@ typescript@4.7.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" integrity sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA== -typo-js@*: - version "1.2.2" - resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.2.tgz#340484d81fe518e77c81a5a770162b14492f183b" - integrity sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw== - uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" @@ -15855,14 +15101,6 @@ vm2@3.9.11: acorn "^8.7.0" acorn-walk "^8.2.0" -vm2@^3.9.4: - version "3.9.14" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.14.tgz#964042b474cf1e6e4f475a39144773cdb9deb734" - integrity sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA== - dependencies: - acorn "^8.7.0" - acorn-walk "^8.2.0" - vuvuzela@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" @@ -16218,11 +15456,6 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" -ws@~8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" - integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== - ws@~8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" @@ -16291,11 +15524,6 @@ xmlbuilder@~9.0.1: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= -xmlhttprequest-ssl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" - integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== - xpath.js@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/xpath.js/-/xpath.js-1.1.0.tgz#3816a44ed4bb352091083d002a383dd5104a5ff1" @@ -16434,11 +15662,6 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" -year@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" - integrity sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w== - ylru@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785" diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index dfb96a061c..48cbd74c4c 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -15,6 +15,7 @@ import Application from "koa" import { bootstrap } from "global-agent" import * as db from "./db" import { auth, logging, events, middleware } from "@budibase/backend-core" +import { sdk } from "@budibase/pro" db.init() import Koa from "koa" import koaBody from "koa-body" @@ -26,6 +27,10 @@ const koaSession = require("koa-session") const logger = require("koa-pino-logger") import destroyable from "server-destroy" +// configure events to use the pro audit log write +// can't integrate directly into backend-core due to cyclic issues +events.configure(sdk.auditLogs.write) + // this will setup http and https proxies form env variables bootstrap() From 2afd3e1580930045944194f4a5a204a8f6136a41 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 15 Feb 2023 19:44:32 +0000 Subject: [PATCH 018/273] Updating events to include a proper friendly map of audited events. --- .../backend-core/src/events/publishers/app.ts | 11 +++ .../src/events/publishers/auth.ts | 6 +- .../src/events/publishers/backup.ts | 5 +- .../src/events/publishers/group.ts | 14 ++- .../src/events/publishers/user.ts | 17 +++- packages/backend-core/src/utils/utils.ts | 3 +- packages/types/src/sdk/events/app.ts | 11 +++ packages/types/src/sdk/events/auth.ts | 2 + packages/types/src/sdk/events/backup.ts | 2 + packages/types/src/sdk/events/event.ts | 98 ++++++++++++++++++- packages/types/src/sdk/events/user.ts | 15 ++- packages/types/src/sdk/events/userGroup.ts | 11 +++ .../worker/src/api/controllers/global/auth.ts | 6 +- packages/worker/src/sdk/users/users.ts | 2 +- 14 files changed, 187 insertions(+), 16 deletions(-) diff --git a/packages/backend-core/src/events/publishers/app.ts b/packages/backend-core/src/events/publishers/app.ts index 90da21f3f5..a4d578bb4f 100644 --- a/packages/backend-core/src/events/publishers/app.ts +++ b/packages/backend-core/src/events/publishers/app.ts @@ -19,6 +19,7 @@ const created = async (app: App, timestamp?: string | number) => { const properties: AppCreatedEvent = { appId: app.appId, version: app.version, + name: app.name, } await publishEvent(Event.APP_CREATED, properties, timestamp) } @@ -27,6 +28,7 @@ async function updated(app: App) { const properties: AppUpdatedEvent = { appId: app.appId, version: app.version, + name: app.name, } await publishEvent(Event.APP_UPDATED, properties) } @@ -34,6 +36,7 @@ async function updated(app: App) { async function deleted(app: App) { const properties: AppDeletedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_DELETED, properties) } @@ -41,6 +44,7 @@ async function deleted(app: App) { async function published(app: App, timestamp?: string | number) { const properties: AppPublishedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_PUBLISHED, properties, timestamp) } @@ -48,6 +52,7 @@ async function published(app: App, timestamp?: string | number) { async function unpublished(app: App) { const properties: AppUnpublishedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_UNPUBLISHED, properties) } @@ -55,6 +60,7 @@ async function unpublished(app: App) { async function fileImported(app: App) { const properties: AppFileImportedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_FILE_IMPORTED, properties) } @@ -63,6 +69,7 @@ async function templateImported(app: App, templateKey: string) { const properties: AppTemplateImportedEvent = { appId: app.appId, templateKey, + name: app.name, } await publishEvent(Event.APP_TEMPLATE_IMPORTED, properties) } @@ -76,6 +83,7 @@ async function versionUpdated( appId: app.appId, currentVersion, updatedToVersion, + name: app.name, } await publishEvent(Event.APP_VERSION_UPDATED, properties) } @@ -89,6 +97,7 @@ async function versionReverted( appId: app.appId, currentVersion, revertedToVersion, + name: app.name, } await publishEvent(Event.APP_VERSION_REVERTED, properties) } @@ -96,6 +105,7 @@ async function versionReverted( async function reverted(app: App) { const properties: AppRevertedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_REVERTED, properties) } @@ -103,6 +113,7 @@ async function reverted(app: App) { async function exported(app: App) { const properties: AppExportedEvent = { appId: app.appId, + name: app.name, } await publishEvent(Event.APP_EXPORTED, properties) } diff --git a/packages/backend-core/src/events/publishers/auth.ts b/packages/backend-core/src/events/publishers/auth.ts index 4436045599..5527e02a34 100644 --- a/packages/backend-core/src/events/publishers/auth.ts +++ b/packages/backend-core/src/events/publishers/auth.ts @@ -12,19 +12,21 @@ import { } from "@budibase/types" import { identification } from ".." -async function login(source: LoginSource) { +async function login(source: LoginSource, email: string) { const identity = await identification.getCurrentIdentity() const properties: LoginEvent = { userId: identity.id, source, + email, } await publishEvent(Event.AUTH_LOGIN, properties) } -async function logout() { +async function logout(email: string) { const identity = await identification.getCurrentIdentity() const properties: LogoutEvent = { userId: identity.id, + email, } await publishEvent(Event.AUTH_LOGOUT, properties) } diff --git a/packages/backend-core/src/events/publishers/backup.ts b/packages/backend-core/src/events/publishers/backup.ts index 12263fe1ff..d7d87f09f1 100644 --- a/packages/backend-core/src/events/publishers/backup.ts +++ b/packages/backend-core/src/events/publishers/backup.ts @@ -13,6 +13,7 @@ async function appBackupRestored(backup: AppBackup) { appId: backup.appId, restoreId: backup._id!, backupCreatedAt: backup.timestamp, + name: backup.name as string, } await publishEvent(Event.APP_BACKUP_RESTORED, properties) @@ -22,13 +23,15 @@ async function appBackupTriggered( appId: string, backupId: string, type: AppBackupType, - trigger: AppBackupTrigger + trigger: AppBackupTrigger, + name: string ) { const properties: AppBackupTriggeredEvent = { appId: appId, backupId, type, trigger, + name, } await publishEvent(Event.APP_BACKUP_TRIGGERED, properties) } diff --git a/packages/backend-core/src/events/publishers/group.ts b/packages/backend-core/src/events/publishers/group.ts index d79920562b..d8de4ccba4 100644 --- a/packages/backend-core/src/events/publishers/group.ts +++ b/packages/backend-core/src/events/publishers/group.ts @@ -8,12 +8,14 @@ import { GroupUsersAddedEvent, GroupUsersDeletedEvent, GroupAddedOnboardingEvent, + GroupPermissionsEditedEvent, UserGroupRoles, } from "@budibase/types" async function created(group: UserGroup, timestamp?: number) { const properties: GroupCreatedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_CREATED, properties, timestamp) } @@ -21,6 +23,7 @@ async function created(group: UserGroup, timestamp?: number) { async function updated(group: UserGroup) { const properties: GroupUpdatedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_UPDATED, properties) } @@ -28,6 +31,7 @@ async function updated(group: UserGroup) { async function deleted(group: UserGroup) { const properties: GroupDeletedEvent = { groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_DELETED, properties) } @@ -36,6 +40,7 @@ async function usersAdded(count: number, group: UserGroup) { const properties: GroupUsersAddedEvent = { count, groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_USERS_ADDED, properties) } @@ -44,6 +49,7 @@ async function usersDeleted(count: number, group: UserGroup) { const properties: GroupUsersDeletedEvent = { count, groupId: group._id as string, + name: group.name, } await publishEvent(Event.USER_GROUP_USERS_REMOVED, properties) } @@ -56,9 +62,11 @@ async function createdOnboarding(groupId: string) { await publishEvent(Event.USER_GROUP_ONBOARDING, properties) } -async function permissionsEdited(roles: UserGroupRoles) { - const properties: UserGroupRoles = { - ...roles, +async function permissionsEdited(group: UserGroup) { + const properties: GroupPermissionsEditedEvent = { + permissions: group.roles!, + name: group.name, + groupId: group._id as string, } await publishEvent(Event.USER_GROUP_PERMISSIONS_EDITED, properties) } diff --git a/packages/backend-core/src/events/publishers/user.ts b/packages/backend-core/src/events/publishers/user.ts index 1fe50149b5..ec43dbbf00 100644 --- a/packages/backend-core/src/events/publishers/user.ts +++ b/packages/backend-core/src/events/publishers/user.ts @@ -19,6 +19,7 @@ import { async function created(user: User, timestamp?: number) { const properties: UserCreatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_CREATED, properties, timestamp) } @@ -26,6 +27,7 @@ async function created(user: User, timestamp?: number) { async function updated(user: User) { const properties: UserUpdatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_UPDATED, properties) } @@ -33,6 +35,7 @@ async function updated(user: User) { async function deleted(user: User) { const properties: UserDeletedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_DELETED, properties) } @@ -40,6 +43,7 @@ async function deleted(user: User) { export async function onboardingComplete(user: User) { const properties: UserOnboardingEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_ONBOARDING_COMPLETE, properties) } @@ -49,6 +53,7 @@ export async function onboardingComplete(user: User) { async function permissionAdminAssigned(user: User, timestamp?: number) { const properties: UserPermissionAssignedEvent = { userId: user._id as string, + email: user.email, } await publishEvent( Event.USER_PERMISSION_ADMIN_ASSIGNED, @@ -60,6 +65,7 @@ async function permissionAdminAssigned(user: User, timestamp?: number) { async function permissionAdminRemoved(user: User) { const properties: UserPermissionRemovedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PERMISSION_ADMIN_REMOVED, properties) } @@ -67,6 +73,7 @@ async function permissionAdminRemoved(user: User) { async function permissionBuilderAssigned(user: User, timestamp?: number) { const properties: UserPermissionAssignedEvent = { userId: user._id as string, + email: user.email, } await publishEvent( Event.USER_PERMISSION_BUILDER_ASSIGNED, @@ -78,20 +85,22 @@ async function permissionBuilderAssigned(user: User, timestamp?: number) { async function permissionBuilderRemoved(user: User) { const properties: UserPermissionRemovedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PERMISSION_BUILDER_REMOVED, properties) } // INVITE -async function invited() { - const properties: UserInvitedEvent = {} +async function invited(email: string) { + const properties: UserInvitedEvent = { email } await publishEvent(Event.USER_INVITED, properties) } async function inviteAccepted(user: User) { const properties: UserInviteAcceptedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_INVITED_ACCEPTED, properties) } @@ -101,6 +110,7 @@ async function inviteAccepted(user: User) { async function passwordForceReset(user: User) { const properties: UserPasswordForceResetEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_FORCE_RESET, properties) } @@ -108,6 +118,7 @@ async function passwordForceReset(user: User) { async function passwordUpdated(user: User) { const properties: UserPasswordUpdatedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_UPDATED, properties) } @@ -115,6 +126,7 @@ async function passwordUpdated(user: User) { async function passwordResetRequested(user: User) { const properties: UserPasswordResetRequestedEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_RESET_REQUESTED, properties) } @@ -122,6 +134,7 @@ async function passwordResetRequested(user: User) { async function passwordReset(user: User) { const properties: UserPasswordResetEvent = { userId: user._id as string, + email: user.email, } await publishEvent(Event.USER_PASSWORD_RESET, properties) } diff --git a/packages/backend-core/src/utils/utils.ts b/packages/backend-core/src/utils/utils.ts index c608686431..0556a80c74 100644 --- a/packages/backend-core/src/utils/utils.ts +++ b/packages/backend-core/src/utils/utils.ts @@ -227,6 +227,7 @@ export async function getBuildersCount() { */ export async function platformLogout(opts: PlatformLogoutOpts) { const ctx = opts.ctx + const email = ctx.user?.email! const userId = opts.userId const keepActiveSession = opts.keepActiveSession @@ -247,7 +248,7 @@ export async function platformLogout(opts: PlatformLogoutOpts) { const sessionIds = sessions.map(({ sessionId }) => sessionId) await invalidateSessions(userId, { sessionIds, reason: "logout" }) - await events.auth.logout() + await events.auth.logout(email) await userCache.invalidateUser(userId) } diff --git a/packages/types/src/sdk/events/app.ts b/packages/types/src/sdk/events/app.ts index 73d491070f..7b63a4f0cd 100644 --- a/packages/types/src/sdk/events/app.ts +++ b/packages/types/src/sdk/events/app.ts @@ -3,50 +3,61 @@ import { BaseEvent } from "./event" export interface AppCreatedEvent extends BaseEvent { appId: string version: string + name: string } export interface AppUpdatedEvent extends BaseEvent { appId: string version: string + name: string } export interface AppDeletedEvent extends BaseEvent { appId: string + name: string } export interface AppPublishedEvent extends BaseEvent { appId: string + name: string } export interface AppUnpublishedEvent extends BaseEvent { appId: string + name: string } export interface AppFileImportedEvent extends BaseEvent { appId: string + name: string } export interface AppTemplateImportedEvent extends BaseEvent { appId: string templateKey: string + name: string } export interface AppVersionUpdatedEvent extends BaseEvent { appId: string currentVersion: string updatedToVersion: string + name: string } export interface AppVersionRevertedEvent extends BaseEvent { appId: string currentVersion: string revertedToVersion: string + name: string } export interface AppRevertedEvent extends BaseEvent { appId: string + name: string } export interface AppExportedEvent extends BaseEvent { appId: string + name: string } diff --git a/packages/types/src/sdk/events/auth.ts b/packages/types/src/sdk/events/auth.ts index eb9f3148a3..a98e1ca889 100644 --- a/packages/types/src/sdk/events/auth.ts +++ b/packages/types/src/sdk/events/auth.ts @@ -7,10 +7,12 @@ export type SSOType = ConfigType.OIDC | ConfigType.GOOGLE export interface LoginEvent extends BaseEvent { userId: string source: LoginSource + email: string } export interface LogoutEvent extends BaseEvent { userId: string + email: string } export interface SSOCreatedEvent extends BaseEvent { diff --git a/packages/types/src/sdk/events/backup.ts b/packages/types/src/sdk/events/backup.ts index 1dddc109cc..23863cf8ac 100644 --- a/packages/types/src/sdk/events/backup.ts +++ b/packages/types/src/sdk/events/backup.ts @@ -5,6 +5,7 @@ export interface AppBackupRestoreEvent extends BaseEvent { appId: string restoreId: string backupCreatedAt: string + name: string } export interface AppBackupTriggeredEvent extends BaseEvent { @@ -12,4 +13,5 @@ export interface AppBackupTriggeredEvent extends BaseEvent { appId: string trigger: AppBackupTrigger type: AppBackupType + name: string } diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 614dd18ded..f7a2051dfc 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -182,8 +182,102 @@ export enum Event { ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", } -export const AuditedEventFriendlyName = { - [Event.USER_CREATED]: "user created", +export class AuditedEventFriendlyName { + // USER + static USER_CREATED = "User {{ email }} created" + static USER_UPDATED = "User {{ email }} updated" + static USER_DELETED = "User {{ email }} deleted" + static USER_PERMISSION_ADMIN_ASSIGNED = "User {{ email }} admin role assigned" + static USER_PERMISSION_ADMIN_REMOVED = "User {{ email }} admin role removed" + static USER_PERMISSION_BUILDER_ASSIGNED = + "User {{ email }} builder role assigned" + static USER_PERMISSION_BUILDER_REMOVED = + "User {{ email }} builder role removed" + static USER_INVITED = "User {{ email }} invited" + static USER_INVITED_ACCEPTED = "User {{ email }} accepted invite" + static USER_PASSWORD_UPDATED = "User {{ email }} password updated" + static USER_PASSWORD_RESET_REQUESTED = + "User {{ email }} password reset requested" + static USER_PASSWORD_RESET = "User {{ email }} password reset" + static USER_GROUP_CREATED = "User group {{ name }} created" + static USER_GROUP_UPDATED = "User group {{ name }} updated" + static USER_GROUP_DELETED = "User group {{ name }} deleted" + static USER_GROUP_USERS_ADDED = + "User group {{ name }} {{ count }} users added" + static USER_GROUP_USERS_REMOVED = + "User group {{ name }} {{ count }} users removed" + static USER_GROUP_PERMISSIONS_EDITED = + "User group {{ name }} permissions edited" + + // EMAIL + static EMAIL_SMTP_CREATED = "Email configuration created" + static EMAIL_SMTP_UPDATED = "Email configuration updated" + + // AUTH + static AUTH_SSO_CREATED = "SSO configuration created" + static AUTH_SSO_UPDATED = "SSO configuration updated" + static AUTH_SSO_ACTIVATED = "SSO configuration activated" + static AUTH_SSO_DEACTIVATED = "SSO configuration deactivated" + static AUTH_LOGIN = "User {{ email }} logged in" + static AUTH_LOGOUT = "User {{ email }} logged out" + + // ORG + static ORG_NAME_UPDATED = "Organisation name updated" + static ORG_LOGO_UPDATED = "Organisation logo updated" + static ORG_PLATFORM_URL_UPDATED = "Organisation platform URL updated" + + // APP + static APP_CREATED = "App {{ name }} created" + static APP_UPDATED = "App {{ name }} updated" + static APP_DELETED = "App {{ name }} deleted" + static APP_PUBLISHED = "App {{ name }} published" + static APP_UNPUBLISHED = "App {{ name }} unpublished" + static APP_TEMPLATE_IMPORTED = "App {{ name }} template imported" + static APP_FILE_IMPORTED = "App {{ name }} file imported" + static APP_VERSION_UPDATED = "App {{ name }} version updated" + static APP_VERSION_REVERTED = "App {{ name }} version reverted" + static APP_REVERTED = "App {{ name }} reverted" + static APP_EXPORTED = "App {{ name }} exported" + static APP_BACKUP_RESTORED = "App backup {{ name }} restored" + static APP_BACKUP_TRIGGERED = "App backup {{ name }} triggered" + + // DATASOURCE + static DATASOURCE_CREATED = "Datasource created" + static DATASOURCE_UPDATED = "Datasource updated" + static DATASOURCE_DELETED = "Datasource deleted" + + // QUERY + static QUERY_CREATED = "Query created" + static QUERY_UPDATED = "Query updated" + static QUERY_DELETED = "Query deleted" + static QUERY_IMPORT = "Query import" + + // TABLE + static TABLE_CREATED = "Table created" + static TABLE_UPDATED = "Table updated" + static TABLE_DELETED = "Table deleted" + static TABLE_EXPORTED = "Table exported" + static TABLE_IMPORTED = "Table imported" + static TABLE_DATA_IMPORTED = "Data imported to table" + + // ROWS + static ROWS_CREATED = "Rows created" + static ROWS_IMPORTED = "Rows imported" + + // AUTOMATION + static AUTOMATION_CREATED = "Automation created" + static AUTOMATION_DELETED = "Automation deleted" + + // SCREEN + static SCREEN_CREATED = "Screen created" + static SCREEN_DELETED = "Screen deleted" + + // COMPONENT + static COMPONENT_CREATED = "Component created" + static COMPONENT_DELETED = "Component deleted" + + static ENVIRONMENT_VARIABLE_CREATED = "Environment variable created" + static ENVIRONMENT_VARIABLE_DELETED = "Environment variable deleted" } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/user.ts b/packages/types/src/sdk/events/user.ts index 3f8f72801c..1322934d45 100644 --- a/packages/types/src/sdk/events/user.ts +++ b/packages/types/src/sdk/events/user.ts @@ -2,47 +2,60 @@ import { BaseEvent } from "./event" export interface UserCreatedEvent extends BaseEvent { userId: string + email: string } export interface UserUpdatedEvent extends BaseEvent { userId: string + email: string } export interface UserDeletedEvent extends BaseEvent { userId: string + email: string } export interface UserOnboardingEvent extends BaseEvent { userId: string step?: string + email: string } export interface UserPermissionAssignedEvent extends BaseEvent { userId: string + email: string } export interface UserPermissionRemovedEvent extends BaseEvent { userId: string + email: string } -export interface UserInvitedEvent extends BaseEvent {} +export interface UserInvitedEvent extends BaseEvent { + email: string +} export interface UserInviteAcceptedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordForceResetEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordUpdatedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordResetRequestedEvent extends BaseEvent { userId: string + email: string } export interface UserPasswordResetEvent extends BaseEvent { userId: string + email: string } diff --git a/packages/types/src/sdk/events/userGroup.ts b/packages/types/src/sdk/events/userGroup.ts index 2ce642e274..57deef4c20 100644 --- a/packages/types/src/sdk/events/userGroup.ts +++ b/packages/types/src/sdk/events/userGroup.ts @@ -2,27 +2,38 @@ import { BaseEvent } from "./event" export interface GroupCreatedEvent extends BaseEvent { groupId: string + name: string } export interface GroupUpdatedEvent extends BaseEvent { groupId: string + name: string } export interface GroupDeletedEvent extends BaseEvent { groupId: string + name: string } export interface GroupUsersAddedEvent extends BaseEvent { count: number groupId: string + name: string } export interface GroupUsersDeletedEvent extends BaseEvent { count: number groupId: string + name: string } export interface GroupAddedOnboardingEvent extends BaseEvent { groupId: string onboarding: boolean } + +export interface GroupPermissionsEditedEvent extends BaseEvent { + permissions: Record + name: string + groupId: string +} diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index e6d3c329d7..7491a47bb3 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -54,7 +54,7 @@ export const authenticate = async (ctx: any, next: any) => { async (err: any, user: User, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("local") + await events.auth.login("local", user.email) }) ctx.status = 200 } @@ -208,7 +208,7 @@ export const googleAuth = async (ctx: any, next: any) => { async (err: any, user: User, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("google-internal") + await events.auth.login("google-internal", user.email) }) ctx.redirect("/") } @@ -272,7 +272,7 @@ export const oidcAuth = async (ctx: any, next: any) => { async (err: any, user: any, info: any) => { await authInternal(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { - await events.auth.login("oidc") + await events.auth.login("oidc", user.email) }) ctx.redirect("/") } diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 8410d0b2e0..617f07d404 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -623,7 +623,7 @@ export const invite = async ( } await sendEmail(user.email, EmailTemplatePurpose.INVITATION, opts) response.successful.push({ email: user.email }) - await events.user.invited() + await events.user.invited(user.email) } catch (e) { console.error(`Failed to send email invitation email=${user.email}`, e) response.unsuccessful.push({ From 6b5128a0bfc76a962aa5efcedf54f5ad0e0c1cc2 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 15 Feb 2023 23:38:59 +0000 Subject: [PATCH 019/273] running API tests with reporting qa nightly tests --- .github/workflows/smoke_test.yaml | 35 +++-------- .../DataTable/modals/CreateEditColumn.svelte | 37 ----------- qa-core/package.json | 2 +- .../scripts/testResultsWebhook.js | 63 +++++++++---------- qa-core/testReport.json | 1 + 5 files changed, 38 insertions(+), 100 deletions(-) rename packages/builder/scripts/cypressResultsWebhook.js => qa-core/scripts/testResultsWebhook.js (72%) create mode 100644 qa-core/testReport.json diff --git a/.github/workflows/smoke_test.yaml b/.github/workflows/smoke_test.yaml index 29c7f5f85a..b4ed39fd68 100644 --- a/.github/workflows/smoke_test.yaml +++ b/.github/workflows/smoke_test.yaml @@ -7,7 +7,7 @@ on: jobs: nightly: - runs-on: ubuntu-latest + runs-on: [self-hosted, qa] steps: - uses: actions/checkout@v2 @@ -15,30 +15,11 @@ jobs: uses: actions/setup-node@v1 with: node-version: 14.x - - run: yarn - - run: yarn bootstrap - - run: yarn build - - name: Pull from budibase-infra + - name: QA Core Integration Tests run: | - curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \ - -H 'Accept: application/vnd.github.v3.raw' \ - -o - -L - wc -l - - - uses: actions/upload-artifact@v3 - with: - name: Test Reports - path: - - # TODO: enable once running in QA test env - # - name: Configure AWS Credentials - # uses: aws-actions/configure-aws-credentials@v1 - # with: - # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - # aws-region: eu-west-1 - - # - name: Upload test results HTML - # uses: aws-actions/configure-aws-credentials@v1 - # run: aws s3 cp packages/builder/cypress/reports/testReport.html s3://{{ secrets.BUDI_QA_REPORTS_BUCKET_NAME }}/$GITHUB_RUN_ID/index.html + cd qa-core + yarn + yarn api:test:ci + env: + BUDIBASE_HOST: budicloud.qa.budibase.net + BUDIBASE_ACCOUNTS_URL: https://account-portal.budicloud.qa.budibase.net \ No newline at end of file diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 95e53b4192..d7225a6645 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -18,7 +18,6 @@ import { TableNames, UNEDITABLE_USER_FIELDS } from "constants" import { FIELDS, - AUTO_COLUMN_SUB_TYPES, RelationshipTypes, ALLOWABLE_STRING_OPTIONS, ALLOWABLE_NUMBER_OPTIONS, @@ -132,12 +131,6 @@ : availableAutoColumns // used to select what different options can be displayed for column type - $: canBeSearched = - editableColumn?.type !== LINK_TYPE && - editableColumn?.type !== JSON_TYPE && - editableColumn?.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY && - editableColumn?.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY && - editableColumn?.type !== FORMULA_TYPE $: canBeDisplay = editableColumn?.type !== LINK_TYPE && editableColumn?.type !== AUTO_TYPE && @@ -254,18 +247,6 @@ } } - function onChangePrimaryIndex(e) { - indexes = e.detail ? [editableColumn.name] : [] - } - - function onChangeSecondaryIndex(e) { - if (e.detail) { - indexes[1] = editableColumn.name - } else { - indexes = indexes.slice(0, 1) - } - } - function openJsonSchemaEditor() { jsonSchemaModal.show() } @@ -460,24 +441,6 @@
{/if} - {#if canBeSearched && !external} -
- - - -
- {/if} - {#if editableColumn.type === "string"} 0 ? "failure" : "success" + const OUTCOME = success ? "success" : "failure" const options = { method: "POST", @@ -68,51 +61,51 @@ async function discordCypressResultsNotification(report) { name: "Commit", value: `https://github.com/Budibase/budibase/commit/${GIT_SHA}`, }, - { - name: "Cypress Dashboard URL", - value: DASHBOARD_URL || "None Supplied", - }, { name: "Github Actions Run URL", value: GITHUB_ACTIONS_RUN_URL || "None Supplied", }, { name: "Test Suites", - value: suites, + value: numTotalTestSuites, }, { name: "Tests", - value: tests, + value: numTotalTests, }, { name: "Passed", - value: passes, + value: numPassedTests, }, { name: "Pending", - value: pending, - }, - { - name: "Skipped", - value: skipped, + value: numPendingTests, }, { name: "Failures", - value: failures, + value: numFailedTests, }, { name: "Duration", - value: `${duration / 1000} Seconds`, + value: endTime + ? `${(endTime - startTime) / 1000} Seconds` + : "DNF", }, { name: "Pass Percentage", - value: Math.floor(passPercent), + value: Math.floor((numPassedTests / numTotalTests) * 100), }, ], }, ], }), } + + // Only post in discord when tests fail + if (success) { + return + } + const response = await fetch(WEBHOOK_URL, options) if (response.status >= 201) { @@ -125,7 +118,7 @@ async function discordCypressResultsNotification(report) { async function run() { const report = await generateReport() - await discordCypressResultsNotification(report) + await discordResultsNotification(report) } run() diff --git a/qa-core/testReport.json b/qa-core/testReport.json new file mode 100644 index 0000000000..b1aa321bc5 --- /dev/null +++ b/qa-core/testReport.json @@ -0,0 +1 @@ +{"numFailedTestSuites":1,"numFailedTests":1,"numPassedTestSuites":11,"numPassedTests":41,"numPendingTestSuites":3,"numPendingTests":11,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":15,"numTotalTests":53,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1676469571194,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["Public API - /rows endpoints"],"duration":548,"failureMessages":[],"fullName":"Public API - /rows endpoints POST - Create a row","location":null,"status":"passed","title":"POST - Create a row"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":60002,"failureMessages":["Error: thrown: \"Exceeded timeout of 60000 ms for a test.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.\"\n at /Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts:35:3\n at _dispatchDescribe (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/index.js:105:26)\n at describe (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/index.js:60:5)\n at Object. (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts:6:1)\n at Runtime._execModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1714:24)\n at Runtime._loadModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1223:12)\n at Runtime.requireModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1047:12)\n at jestAdapter (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:89:13)\n at runTestInternal (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runner/build/runTest.js:411:16)\n at runTest (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runner/build/runTest.js:499:34)"],"fullName":"Public API - /rows endpoints POST - Search rows","location":null,"status":"failed","title":"POST - Search rows"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":496,"failureMessages":[],"fullName":"Public API - /rows endpoints GET - Retrieve a row","location":null,"status":"passed","title":"GET - Retrieve a row"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":644,"failureMessages":[],"fullName":"Public API - /rows endpoints PUT - update a row","location":null,"status":"passed","title":"PUT - update a row"}],"endTime":1676469635424,"message":"\u001b[1m\u001b[31m \u001b[1m● \u001b[22m\u001b[1mPublic API - /rows endpoints › POST - Search rows\u001b[39m\u001b[22m\n\n thrown: \"Exceeded timeout of 60000 ms for a test.\n Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.\"\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 33 |\u001b[39m })\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 34 |\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m\u001b[31m\u001b[1m>\u001b[22m\u001b[2m\u001b[39m\u001b[90m 35 |\u001b[39m it(\u001b[32m\"POST - Search rows\"\u001b[39m\u001b[33m,\u001b[39m \u001b[36masync\u001b[39m () \u001b[33m=>\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m |\u001b[39m \u001b[31m\u001b[1m^\u001b[22m\u001b[2m\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 36 |\u001b[39m \u001b[36mconst\u001b[39m [response\u001b[33m,\u001b[39m rows] \u001b[33m=\u001b[39m \u001b[36mawait\u001b[39m config\u001b[33m.\u001b[39mrows\u001b[33m.\u001b[39msearch({\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 37 |\u001b[39m query\u001b[33m:\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 38 |\u001b[39m string\u001b[33m:\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat \u001b[22m\u001b[2m\u001b[0m\u001b[36msrc/tests/public-api/tables/rows.spec.ts\u001b[39m\u001b[0m\u001b[2m:35:3\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat Object. (\u001b[22m\u001b[2m\u001b[0m\u001b[36msrc/tests/public-api/tables/rows.spec.ts\u001b[39m\u001b[0m\u001b[2m:6:1)\u001b[22m\u001b[2m\u001b[22m\n","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts","startTime":1676469571238,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":3773,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add BASIC user to app","location":null,"status":"passed","title":"Add BASIC user to app"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":4896,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add ADMIN user to app","location":null,"status":"passed","title":"Add ADMIN user to app"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":2606,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add POWER user to app","location":null,"status":"passed","title":"Add POWER user to app"}],"endTime":1676469650546,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/appSpecificRoles.spec.ts","startTime":1676469635431,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Table Operations"],"duration":4474,"failureMessages":[],"fullName":"Internal API - Table Operations Create and delete table, columns and rows","location":null,"status":"passed","title":"Create and delete table, columns and rows"},{"ancestorTitles":["Internal API - Table Operations"],"duration":7624,"failureMessages":[],"fullName":"Internal API - Table Operations Search and pagination","location":null,"status":"passed","title":"Search and pagination"}],"endTime":1676469664993,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/tables/tables.spec.ts","startTime":1676469650551,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":4680,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Publish app","location":null,"status":"passed","title":"Publish app"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1641,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Sync application before deployment","location":null,"status":"passed","title":"Sync application before deployment"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":2805,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Sync application after deployment","location":null,"status":"passed","title":"Sync application after deployment"}],"endTime":1676469676987,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/publish.spec.ts","startTime":1676469664996,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /applications endpoints"],"duration":792,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - Create an application","location":null,"status":"passed","title":"POST - Create an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":29,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - Search applications","location":null,"status":"passed","title":"POST - Search applications"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":140,"failureMessages":[],"fullName":"Public API - /applications endpoints GET - Retrieve an application","location":null,"status":"passed","title":"GET - Retrieve an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":305,"failureMessages":[],"fullName":"Public API - /applications endpoints PUT - update an application","location":null,"status":"passed","title":"PUT - update an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":12038,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - publish an application","location":null,"status":"passed","title":"POST - publish an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":14193,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - unpublish a published application","location":null,"status":"passed","title":"POST - unpublish a published application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":128,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - unpublish an unpublished application","location":null,"status":"passed","title":"POST - unpublish an unpublished application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":21572,"failureMessages":[],"fullName":"Public API - /applications endpoints DELETE - delete a published application and the dev application","location":null,"status":"passed","title":"DELETE - delete a published application and the dev application"}],"endTime":1676469727469,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/applications/applications.spec.ts","startTime":1676469676996,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1421,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Update an application","location":null,"status":"passed","title":"Update an application"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1268,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Revert Changes without changes","location":null,"status":"passed","title":"Revert Changes without changes"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":4735,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Revert Changes","location":null,"status":"passed","title":"Revert Changes"}],"endTime":1676469737505,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/update.spec.ts","startTime":1676469727506,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":2158,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Add Users with different roles","location":null,"status":"passed","title":"Add Users with different roles"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1010,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Delete User","location":null,"status":"passed","title":"Delete User"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1200,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Reset Password","location":null,"status":"passed","title":"Reset Password"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1258,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Change User information","location":null,"status":"passed","title":"Change User information"}],"endTime":1676469745995,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/userManagement.spec.ts","startTime":1676469737513,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - /screens endpoints"],"duration":2086,"failureMessages":[],"fullName":"Internal API - /screens endpoints Create a screen with each role type","location":null,"status":"passed","title":"Create a screen with each role type"},{"ancestorTitles":["Internal API - /screens endpoints"],"duration":1530,"failureMessages":[],"fullName":"Internal API - /screens endpoints Get screens","location":null,"status":"passed","title":"Get screens"},{"ancestorTitles":["Internal API - /screens endpoints"],"duration":1632,"failureMessages":[],"fullName":"Internal API - /screens endpoints Delete a screen","location":null,"status":"passed","title":"Delete a screen"}],"endTime":1676469753597,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/screens/screens.spec.ts","startTime":1676469746008,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation"],"duration":324,"failureMessages":[],"fullName":"Internal API - Application creation Get applications without applications","location":null,"status":"passed","title":"Get applications without applications"},{"ancestorTitles":["Internal API - Application creation"],"duration":1253,"failureMessages":[],"fullName":"Internal API - Application creation Get all Applications after creating an application","location":null,"status":"passed","title":"Get all Applications after creating an application"},{"ancestorTitles":["Internal API - Application creation"],"duration":1254,"failureMessages":[],"fullName":"Internal API - Application creation Get application details","location":null,"status":"passed","title":"Get application details"}],"endTime":1676469758806,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/create.spec.ts","startTime":1676469753605,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1747,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete DELETE - Delete an application","location":null,"status":"passed","title":"DELETE - Delete an application"}],"endTime":1676469762953,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/delete.spec.ts","startTime":1676469758814,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 1 permissions","location":null,"status":"pending","title":"Custom role access for level 1 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 2 permissions","location":null,"status":"pending","title":"Custom role access for level 2 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 3 permissions","location":null,"status":"pending","title":"Custom role access for level 3 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 4 permissions","location":null,"status":"pending","title":"Custom role access for level 4 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 5 permissions","location":null,"status":"pending","title":"Custom role access for level 5 permissions"}],"endTime":1676469763432,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/customRoles.spec.ts","startTime":1676469762962,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for BASIC Role","location":null,"status":"pending","title":"Check Screen access for BASIC Role"},{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for POWER role","location":null,"status":"pending","title":"Check Screen access for POWER role"},{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for ADMIN role","location":null,"status":"pending","title":"Check Screen access for ADMIN role"}],"endTime":1676469763656,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/screenAccess.spec.ts","startTime":1676469763438,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for app user","location":null,"status":"pending","title":"Check Table access for app user"},{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for developer","location":null,"status":"pending","title":"Check Table access for developer"},{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for admin","location":null,"status":"pending","title":"Check Table access for admin"}],"endTime":1676469763691,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/tableAccess.spec.ts","startTime":1676469763660,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /tables endpoints"],"duration":242,"failureMessages":[],"fullName":"Public API - /tables endpoints POST - Create a table","location":null,"status":"passed","title":"POST - Create a table"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":104,"failureMessages":[],"fullName":"Public API - /tables endpoints POST - Search tables","location":null,"status":"passed","title":"POST - Search tables"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":114,"failureMessages":[],"fullName":"Public API - /tables endpoints GET - Retrieve a table","location":null,"status":"passed","title":"GET - Retrieve a table"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":337,"failureMessages":[],"fullName":"Public API - /tables endpoints PUT - update a table","location":null,"status":"passed","title":"PUT - update a table"}],"endTime":1676469765643,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/tables.spec.ts","startTime":1676469763694,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /users endpoints"],"duration":352,"failureMessages":[],"fullName":"Public API - /users endpoints POST - Create a user","location":null,"status":"passed","title":"POST - Create a user"},{"ancestorTitles":["Public API - /users endpoints"],"duration":191,"failureMessages":[],"fullName":"Public API - /users endpoints POST - Search users","location":null,"status":"passed","title":"POST - Search users"},{"ancestorTitles":["Public API - /users endpoints"],"duration":99,"failureMessages":[],"fullName":"Public API - /users endpoints GET - Retrieve a user","location":null,"status":"passed","title":"GET - Retrieve a user"},{"ancestorTitles":["Public API - /users endpoints"],"duration":314,"failureMessages":[],"fullName":"Public API - /users endpoints PUT - update a user","location":null,"status":"passed","title":"PUT - update a user"}],"endTime":1676469766998,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/users/users.spec.ts","startTime":1676469765647,"status":"passed","summary":""}],"wasInterrupted":false} \ No newline at end of file From 9ca6aa8bbc7d6e22496a1f53e80a954c1133b8e0 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 15 Feb 2023 23:43:53 +0000 Subject: [PATCH 020/273] tidy up --- .github/workflows/smoke_test.yaml | 8 +++++++- qa-core/.gitignore | 3 ++- qa-core/package.json | 1 + qa-core/scripts/testResultsWebhook.js | 2 +- qa-core/testReport.json | 1 - 5 files changed, 11 insertions(+), 4 deletions(-) delete mode 100644 qa-core/testReport.json diff --git a/.github/workflows/smoke_test.yaml b/.github/workflows/smoke_test.yaml index b4ed39fd68..3fd61cd9c5 100644 --- a/.github/workflows/smoke_test.yaml +++ b/.github/workflows/smoke_test.yaml @@ -22,4 +22,10 @@ jobs: yarn api:test:ci env: BUDIBASE_HOST: budicloud.qa.budibase.net - BUDIBASE_ACCOUNTS_URL: https://account-portal.budicloud.qa.budibase.net \ No newline at end of file + BUDIBASE_ACCOUNTS_URL: https://account-portal.budicloud.qa.budibase.net + + - name: Cypress Discord Notify + run: yarn test:notify + env: + WEBHOOK_URL: ${{ secrets.BUDI_QA_WEBHOOK }} + GITHUB_RUN_URL: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID \ No newline at end of file diff --git a/qa-core/.gitignore b/qa-core/.gitignore index e82880bc81..08660a00a8 100644 --- a/qa-core/.gitignore +++ b/qa-core/.gitignore @@ -1,4 +1,5 @@ node_modules/ .env watchtower-hook.json -dist/ \ No newline at end of file +dist/ +.testReport.json diff --git a/qa-core/package.json b/qa-core/package.json index 846ccb4dbe..2ae04ece6c 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -12,6 +12,7 @@ "test": "env-cmd jest --runInBand --json --outputFile=testResults.json", "test:watch": "env-cmd jest --watch", "test:debug": "DEBUG=1 jest", + "test:notify": "node scripts/testResultsWebhook", "docker:up": "docker-compose up -d", "docker:down": "docker-compose down", "api:server:setup": "npm run docker:up && env-cmd ts-node ../packages/builder/ts/setup.ts", diff --git a/qa-core/scripts/testResultsWebhook.js b/qa-core/scripts/testResultsWebhook.js index 034fe45064..fc00bf34ad 100644 --- a/qa-core/scripts/testResultsWebhook.js +++ b/qa-core/scripts/testResultsWebhook.js @@ -4,7 +4,7 @@ const fetch = require("node-fetch") const path = require("path") const fs = require("fs") -const WEBHOOK_URL = process.env.CYPRESS_WEBHOOK_URL +const WEBHOOK_URL = process.env.WEBHOOK_URL const GIT_SHA = process.env.GITHUB_SHA const GITHUB_ACTIONS_RUN_URL = process.env.GITHUB_ACTIONS_RUN_URL diff --git a/qa-core/testReport.json b/qa-core/testReport.json deleted file mode 100644 index b1aa321bc5..0000000000 --- a/qa-core/testReport.json +++ /dev/null @@ -1 +0,0 @@ -{"numFailedTestSuites":1,"numFailedTests":1,"numPassedTestSuites":11,"numPassedTests":41,"numPendingTestSuites":3,"numPendingTests":11,"numRuntimeErrorTestSuites":0,"numTodoTests":0,"numTotalTestSuites":15,"numTotalTests":53,"openHandles":[],"snapshot":{"added":0,"didUpdate":false,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":0,"total":0,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0},"startTime":1676469571194,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["Public API - /rows endpoints"],"duration":548,"failureMessages":[],"fullName":"Public API - /rows endpoints POST - Create a row","location":null,"status":"passed","title":"POST - Create a row"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":60002,"failureMessages":["Error: thrown: \"Exceeded timeout of 60000 ms for a test.\nUse jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.\"\n at /Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts:35:3\n at _dispatchDescribe (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/index.js:105:26)\n at describe (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/index.js:60:5)\n at Object. (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts:6:1)\n at Runtime._execModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1714:24)\n at Runtime._loadModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1223:12)\n at Runtime.requireModule (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runtime/build/index.js:1047:12)\n at jestAdapter (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:89:13)\n at runTestInternal (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runner/build/runTest.js:411:16)\n at runTest (/Users/mmckeaveney/Dev/budibase/budibase/qa-core/node_modules/jest-runner/build/runTest.js:499:34)"],"fullName":"Public API - /rows endpoints POST - Search rows","location":null,"status":"failed","title":"POST - Search rows"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":496,"failureMessages":[],"fullName":"Public API - /rows endpoints GET - Retrieve a row","location":null,"status":"passed","title":"GET - Retrieve a row"},{"ancestorTitles":["Public API - /rows endpoints"],"duration":644,"failureMessages":[],"fullName":"Public API - /rows endpoints PUT - update a row","location":null,"status":"passed","title":"PUT - update a row"}],"endTime":1676469635424,"message":"\u001b[1m\u001b[31m \u001b[1m● \u001b[22m\u001b[1mPublic API - /rows endpoints › POST - Search rows\u001b[39m\u001b[22m\n\n thrown: \"Exceeded timeout of 60000 ms for a test.\n Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.\"\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 33 |\u001b[39m })\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 34 |\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m\u001b[31m\u001b[1m>\u001b[22m\u001b[2m\u001b[39m\u001b[90m 35 |\u001b[39m it(\u001b[32m\"POST - Search rows\"\u001b[39m\u001b[33m,\u001b[39m \u001b[36masync\u001b[39m () \u001b[33m=>\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m |\u001b[39m \u001b[31m\u001b[1m^\u001b[22m\u001b[2m\u001b[39m\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 36 |\u001b[39m \u001b[36mconst\u001b[39m [response\u001b[33m,\u001b[39m rows] \u001b[33m=\u001b[39m \u001b[36mawait\u001b[39m config\u001b[33m.\u001b[39mrows\u001b[33m.\u001b[39msearch({\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 37 |\u001b[39m query\u001b[33m:\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m \u001b[0m \u001b[90m 38 |\u001b[39m string\u001b[33m:\u001b[39m {\u001b[0m\u001b[22m\n\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat \u001b[22m\u001b[2m\u001b[0m\u001b[36msrc/tests/public-api/tables/rows.spec.ts\u001b[39m\u001b[0m\u001b[2m:35:3\u001b[22m\u001b[2m\u001b[22m\n\u001b[2m \u001b[2mat Object. (\u001b[22m\u001b[2m\u001b[0m\u001b[36msrc/tests/public-api/tables/rows.spec.ts\u001b[39m\u001b[0m\u001b[2m:6:1)\u001b[22m\u001b[2m\u001b[22m\n","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/rows.spec.ts","startTime":1676469571238,"status":"failed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":3773,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add BASIC user to app","location":null,"status":"passed","title":"Add BASIC user to app"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":4896,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add ADMIN user to app","location":null,"status":"passed","title":"Add ADMIN user to app"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":2606,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Add POWER user to app","location":null,"status":"passed","title":"Add POWER user to app"}],"endTime":1676469650546,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/appSpecificRoles.spec.ts","startTime":1676469635431,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Table Operations"],"duration":4474,"failureMessages":[],"fullName":"Internal API - Table Operations Create and delete table, columns and rows","location":null,"status":"passed","title":"Create and delete table, columns and rows"},{"ancestorTitles":["Internal API - Table Operations"],"duration":7624,"failureMessages":[],"fullName":"Internal API - Table Operations Search and pagination","location":null,"status":"passed","title":"Search and pagination"}],"endTime":1676469664993,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/tables/tables.spec.ts","startTime":1676469650551,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":4680,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Publish app","location":null,"status":"passed","title":"Publish app"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1641,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Sync application before deployment","location":null,"status":"passed","title":"Sync application before deployment"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":2805,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Sync application after deployment","location":null,"status":"passed","title":"Sync application after deployment"}],"endTime":1676469676987,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/publish.spec.ts","startTime":1676469664996,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /applications endpoints"],"duration":792,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - Create an application","location":null,"status":"passed","title":"POST - Create an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":29,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - Search applications","location":null,"status":"passed","title":"POST - Search applications"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":140,"failureMessages":[],"fullName":"Public API - /applications endpoints GET - Retrieve an application","location":null,"status":"passed","title":"GET - Retrieve an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":305,"failureMessages":[],"fullName":"Public API - /applications endpoints PUT - update an application","location":null,"status":"passed","title":"PUT - update an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":12038,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - publish an application","location":null,"status":"passed","title":"POST - publish an application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":14193,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - unpublish a published application","location":null,"status":"passed","title":"POST - unpublish a published application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":128,"failureMessages":[],"fullName":"Public API - /applications endpoints POST - unpublish an unpublished application","location":null,"status":"passed","title":"POST - unpublish an unpublished application"},{"ancestorTitles":["Public API - /applications endpoints"],"duration":21572,"failureMessages":[],"fullName":"Public API - /applications endpoints DELETE - delete a published application and the dev application","location":null,"status":"passed","title":"DELETE - delete a published application and the dev application"}],"endTime":1676469727469,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/applications/applications.spec.ts","startTime":1676469676996,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1421,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Update an application","location":null,"status":"passed","title":"Update an application"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1268,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Revert Changes without changes","location":null,"status":"passed","title":"Revert Changes without changes"},{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":4735,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete Revert Changes","location":null,"status":"passed","title":"Revert Changes"}],"endTime":1676469737505,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/update.spec.ts","startTime":1676469727506,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":2158,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Add Users with different roles","location":null,"status":"passed","title":"Add Users with different roles"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1010,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Delete User","location":null,"status":"passed","title":"Delete User"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1200,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Reset Password","location":null,"status":"passed","title":"Reset Password"},{"ancestorTitles":["Internal API - User Management & Permissions"],"duration":1258,"failureMessages":[],"fullName":"Internal API - User Management & Permissions Change User information","location":null,"status":"passed","title":"Change User information"}],"endTime":1676469745995,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/userManagement.spec.ts","startTime":1676469737513,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - /screens endpoints"],"duration":2086,"failureMessages":[],"fullName":"Internal API - /screens endpoints Create a screen with each role type","location":null,"status":"passed","title":"Create a screen with each role type"},{"ancestorTitles":["Internal API - /screens endpoints"],"duration":1530,"failureMessages":[],"fullName":"Internal API - /screens endpoints Get screens","location":null,"status":"passed","title":"Get screens"},{"ancestorTitles":["Internal API - /screens endpoints"],"duration":1632,"failureMessages":[],"fullName":"Internal API - /screens endpoints Delete a screen","location":null,"status":"passed","title":"Delete a screen"}],"endTime":1676469753597,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/screens/screens.spec.ts","startTime":1676469746008,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation"],"duration":324,"failureMessages":[],"fullName":"Internal API - Application creation Get applications without applications","location":null,"status":"passed","title":"Get applications without applications"},{"ancestorTitles":["Internal API - Application creation"],"duration":1253,"failureMessages":[],"fullName":"Internal API - Application creation Get all Applications after creating an application","location":null,"status":"passed","title":"Get all Applications after creating an application"},{"ancestorTitles":["Internal API - Application creation"],"duration":1254,"failureMessages":[],"fullName":"Internal API - Application creation Get application details","location":null,"status":"passed","title":"Get application details"}],"endTime":1676469758806,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/create.spec.ts","startTime":1676469753605,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Application creation, update, publish and delete"],"duration":1747,"failureMessages":[],"fullName":"Internal API - Application creation, update, publish and delete DELETE - Delete an application","location":null,"status":"passed","title":"DELETE - Delete an application"}],"endTime":1676469762953,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/applications/delete.spec.ts","startTime":1676469758814,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 1 permissions","location":null,"status":"pending","title":"Custom role access for level 1 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 2 permissions","location":null,"status":"pending","title":"Custom role access for level 2 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 3 permissions","location":null,"status":"pending","title":"Custom role access for level 3 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 4 permissions","location":null,"status":"pending","title":"Custom role access for level 4 permissions"},{"ancestorTitles":["Internal API - App Specific Roles & Permissions"],"duration":null,"failureMessages":[],"fullName":"Internal API - App Specific Roles & Permissions Custom role access for level 5 permissions","location":null,"status":"pending","title":"Custom role access for level 5 permissions"}],"endTime":1676469763432,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/customRoles.spec.ts","startTime":1676469762962,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for BASIC Role","location":null,"status":"pending","title":"Check Screen access for BASIC Role"},{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for POWER role","location":null,"status":"pending","title":"Check Screen access for POWER role"},{"ancestorTitles":["Internal API - Role screen access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role screen access Check Screen access for ADMIN role","location":null,"status":"pending","title":"Check Screen access for ADMIN role"}],"endTime":1676469763656,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/screenAccess.spec.ts","startTime":1676469763438,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for app user","location":null,"status":"pending","title":"Check Table access for app user"},{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for developer","location":null,"status":"pending","title":"Check Table access for developer"},{"ancestorTitles":["Internal API - Role table access"],"duration":null,"failureMessages":[],"fullName":"Internal API - Role table access Check Table access for admin","location":null,"status":"pending","title":"Check Table access for admin"}],"endTime":1676469763691,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/internal-api/userManagement/tableAccess.spec.ts","startTime":1676469763660,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /tables endpoints"],"duration":242,"failureMessages":[],"fullName":"Public API - /tables endpoints POST - Create a table","location":null,"status":"passed","title":"POST - Create a table"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":104,"failureMessages":[],"fullName":"Public API - /tables endpoints POST - Search tables","location":null,"status":"passed","title":"POST - Search tables"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":114,"failureMessages":[],"fullName":"Public API - /tables endpoints GET - Retrieve a table","location":null,"status":"passed","title":"GET - Retrieve a table"},{"ancestorTitles":["Public API - /tables endpoints"],"duration":337,"failureMessages":[],"fullName":"Public API - /tables endpoints PUT - update a table","location":null,"status":"passed","title":"PUT - update a table"}],"endTime":1676469765643,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/tables/tables.spec.ts","startTime":1676469763694,"status":"passed","summary":""},{"assertionResults":[{"ancestorTitles":["Public API - /users endpoints"],"duration":352,"failureMessages":[],"fullName":"Public API - /users endpoints POST - Create a user","location":null,"status":"passed","title":"POST - Create a user"},{"ancestorTitles":["Public API - /users endpoints"],"duration":191,"failureMessages":[],"fullName":"Public API - /users endpoints POST - Search users","location":null,"status":"passed","title":"POST - Search users"},{"ancestorTitles":["Public API - /users endpoints"],"duration":99,"failureMessages":[],"fullName":"Public API - /users endpoints GET - Retrieve a user","location":null,"status":"passed","title":"GET - Retrieve a user"},{"ancestorTitles":["Public API - /users endpoints"],"duration":314,"failureMessages":[],"fullName":"Public API - /users endpoints PUT - update a user","location":null,"status":"passed","title":"PUT - update a user"}],"endTime":1676469766998,"message":"","name":"/Users/mmckeaveney/Dev/budibase/budibase/qa-core/src/tests/public-api/users/users.spec.ts","startTime":1676469765647,"status":"passed","summary":""}],"wasInterrupted":false} \ No newline at end of file From e7999504c89862b7f31b0e36d7d7a2f1336666cf Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 16 Feb 2023 10:13:25 +0000 Subject: [PATCH 021/273] wildcard all amazonaws addresses --- hosting/proxy/nginx.prod.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/proxy/nginx.prod.conf b/hosting/proxy/nginx.prod.conf index 21b337deae..2dc97010db 100644 --- a/hosting/proxy/nginx.prod.conf +++ b/hosting/proxy/nginx.prod.conf @@ -55,7 +55,7 @@ http { set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; set $csp_object "object-src 'none'"; set $csp_base_uri "base-uri 'self'"; - set $csp_connect "connect-src 'self' https://*.budibase.net https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.amazonaws.com https://*.s3.us-east-2.amazonaws.com https://*.s3.us-east-1.amazonaws.com https://*.s3.us-west-1.amazonaws.com https://*.s3.us-west-2.amazonaws.com https://*.s3.af-south-1.amazonaws.com https://*.s3.ap-east-1.amazonaws.com https://*.s3.ap-southeast-3.amazonaws.com https://*.s3.ap-south-1.amazonaws.com https://*.s3.ap-northeast-3.amazonaws.com https://*.s3.ap-northeast-2.amazonaws.com https://*.s3.ap-southeast-1.amazonaws.com https://*.s3.ap-southeast-2.amazonaws.com https://*.s3.ap-northeast-1.amazonaws.com https://*.s3.ca-central-1.amazonaws.com https://*.s3.cn-north-1.amazonaws.com https://*.s3.cn-northwest-1.amazonaws.com https://*.s3.eu-central-1.amazonaws.com https://*.s3.eu-west-1.amazonaws.com https://*.s3.eu-west-2.amazonaws.com https://*.s3.eu-south-1.amazonaws.com https://*.s3.eu-west-3.amazonaws.com https://*.s3.eu-north-1.amazonaws.com https://*.s3.sa-east-1.amazonaws.com https://*.s3.me-south-1.amazonaws.com https://*.s3.us-gov-east-1.amazonaws.com https://*.s3.us-gov-west-1.amazonaws.com https://api.github.com"; + set $csp_connect "connect-src 'self' https://*.budibase.net https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.*.amazonaws.com https://api.github.com"; set $csp_font "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com https://js.intercomcdn.com https://fonts.intercomcdn.com"; set $csp_frame "frame-src 'self' https:"; set $csp_img "img-src http: https: data: blob:"; From 55bff3de2950cc8e4de1df64b04c6651d31946b5 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 16 Feb 2023 10:18:48 +0000 Subject: [PATCH 022/273] no wildcard at start of s3 csp --- hosting/proxy/nginx.prod.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hosting/proxy/nginx.prod.conf b/hosting/proxy/nginx.prod.conf index 2dc97010db..4d8b3466bf 100644 --- a/hosting/proxy/nginx.prod.conf +++ b/hosting/proxy/nginx.prod.conf @@ -55,7 +55,7 @@ http { set $csp_style "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com"; set $csp_object "object-src 'none'"; set $csp_base_uri "base-uri 'self'"; - set $csp_connect "connect-src 'self' https://*.budibase.net https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.*.amazonaws.com https://api.github.com"; + set $csp_connect "connect-src 'self' https://*.budibase.net https://api-iam.intercom.io https://api-iam.intercom.io https://api-ping.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io wss://nexus-websocket-b.intercom.io https://nexus-websocket-a.intercom.io https://nexus-websocket-b.intercom.io https://uploads.intercomcdn.com https://uploads.intercomusercontent.com https://*.s3.*.amazonaws.com https://s3.*.amazonaws.com https://api.github.com"; set $csp_font "font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com https://js.intercomcdn.com https://fonts.intercomcdn.com"; set $csp_frame "frame-src 'self' https:"; set $csp_img "img-src http: https: data: blob:"; From c81ef6f128d9bf70641f86280cc44238e0848e92 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 16 Feb 2023 13:33:53 +0000 Subject: [PATCH 023/273] Attempt to fix flakey 409s when deleting screens that are linked in the nav (#9700) --- packages/builder/src/builderStore/store/frontend.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 7d19573cce..56b8a599f0 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -312,7 +312,7 @@ export const getFrontendStore = () => { const screensToDelete = Array.isArray(screens) ? screens : [screens] // Build array of promises to speed up bulk deletions - const promises = [] + let promises = [] let deleteUrls = [] screensToDelete.forEach(screen => { // Delete the screen @@ -326,8 +326,8 @@ export const getFrontendStore = () => { deleteUrls.push(screen.routing.route) }) - promises.push(store.actions.links.delete(deleteUrls)) await Promise.all(promises) + await store.actions.links.delete(deleteUrls) const deletedIds = screensToDelete.map(screen => screen._id) const routesResponse = await API.fetchAppRoutes() store.update(state => { From 89829965d4da4abfd59025687879fd239bf95204 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Thu, 16 Feb 2023 14:14:22 +0000 Subject: [PATCH 024/273] Remove test on release-develop job (temporary) (#9711) * Remove test on release-develop job (temporary) * Remove test on release-develop job (temporary) * Speed up pro release script by adding no verify flag to version update commits --- .github/workflows/release-develop.yml | 3 +-- scripts/pro/release.sh | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-develop.yml b/.github/workflows/release-develop.yml index 1ac6b20003..d679d31139 100644 --- a/.github/workflows/release-develop.yml +++ b/.github/workflows/release-develop.yml @@ -45,10 +45,9 @@ jobs: - run: yarn - run: yarn bootstrap - - run: yarn lint - run: yarn build - run: yarn build:sdk - - run: yarn test +# - run: yarn test - name: Publish budibase packages to NPM env: diff --git a/scripts/pro/release.sh b/scripts/pro/release.sh index 7fbb3c0fd6..e57d8deeb8 100755 --- a/scripts/pro/release.sh +++ b/scripts/pro/release.sh @@ -53,7 +53,7 @@ yarn clean -y && yarn bootstrap # Commit and push git add packages/pro/yarn.lock -git commit -m "Update dependency versions to $VERSION" +git commit -m "Update dependency versions to $VERSION" -n git push ############################################# @@ -91,5 +91,5 @@ git add packages/server/package.json git add packages/server/yarn.lock git add packages/worker/package.json git add packages/worker/yarn.lock -git commit -m "Update pro version to $VERSION" +git commit -m "Update pro version to $VERSION" -n git push From a232d615279661634c40c2275bac95b8a72b3704 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 16 Feb 2023 14:26:19 +0000 Subject: [PATCH 025/273] v2.3.17-alpha.0 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 0377c73101..2ecb0c19a5 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.16", + "version": "2.3.17-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index e6dda5e162..754dfe197f 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "^2.3.16", + "@budibase/types": "2.3.17-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 073f57f094..68da2f91d1 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "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.3.16", + "@budibase/string-templates": "2.3.17-alpha.0", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 7def4ba371..ed700b1397 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "^2.3.16", - "@budibase/client": "^2.3.16", - "@budibase/frontend-core": "^2.3.16", - "@budibase/string-templates": "^2.3.16", + "@budibase/bbui": "2.3.17-alpha.0", + "@budibase/client": "2.3.17-alpha.0", + "@budibase/frontend-core": "2.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.0", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 5209c51b2e..badd55fad8 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "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.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/backend-core": "2.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.0", + "@budibase/types": "2.3.17-alpha.0", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 5e2dad5217..1b5c3708ad 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.16", + "version": "2.3.17-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": "^2.3.16", - "@budibase/frontend-core": "^2.3.16", - "@budibase/string-templates": "^2.3.16", + "@budibase/bbui": "2.3.17-alpha.0", + "@budibase/frontend-core": "2.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.0", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 897b7107cf..94b8e1dcdd 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^2.3.16", + "@budibase/bbui": "2.3.17-alpha.0", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 51f5ca70e0..ca166434d4 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 61d57c4179..bc58239468 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "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.3.16", - "@budibase/client": "^2.3.16", + "@budibase/backend-core": "2.3.17-alpha.0", + "@budibase/client": "2.3.17-alpha.0", "@budibase/pro": "2.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/string-templates": "2.3.17-alpha.0", + "@budibase/types": "2.3.17-alpha.0", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 6b99e321e5..3445666e3a 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 7d679edcf6..8c1c6f588a 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 6da61f1183..817fca19c3 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.16", + "version": "2.3.17-alpha.0", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^2.3.16", + "@budibase/backend-core": "2.3.17-alpha.0", "@budibase/pro": "2.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/string-templates": "2.3.17-alpha.0", + "@budibase/types": "2.3.17-alpha.0", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 5163e0426238a6794f005b23ada6cd08fd735bc0 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 16 Feb 2023 14:30:28 +0000 Subject: [PATCH 026/273] Update pro version to 2.3.17-alpha.0 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 45 ++++++++++++++++++---------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 58 ++++++++++++++++++------------------ 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index bc58239468..219ac04de2 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.0", "@budibase/client": "2.3.17-alpha.0", - "@budibase/pro": "2.3.16", + "@budibase/pro": "2.3.17-alpha.0", "@budibase/string-templates": "2.3.17-alpha.0", "@budibase/types": "2.3.17-alpha.0", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 497507c40d..5c0e299c3a 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,13 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.16.tgz#05a8434501718b9eab0109be03c677c1d546fe17" - integrity sha512-wMuqxKVua3/3XejUMH/fJQgu1kK6t4HYpB5AY58sumNSLbFFp1MyqL+1LMSmpUY0nbjExq+9+wseNsnbWicWUw== +"@budibase/backend-core@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.0.tgz#3a4e9323e9a057af0fdbdfe72c570eeec1c154ff" + integrity sha512-zxbxcmcgP7chm9Vt5Scbvegg482KXPhJTXjF2g8/06MPSPnwHkUGreUpH25X7Jei5OUGKlG89BonAhmyRBGErg== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.16" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.17-alpha.0" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1309,7 +1310,6 @@ posthog-node "1.3.0" pouchdb "7.3.0" pouchdb-find "7.2.2" - pouchdb-replication-stream "1.2.9" redlock "4.2.0" sanitize-s3-objectkey "0.0.1" semver "7.3.7" @@ -1379,13 +1379,26 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.16.tgz#3eca93b826ed6da5b6941d8b384c34c57da2b1b4" - integrity sha512-lIbPXOs61WP7jE80XHRDkBRmSEMYjiaog+qw0dUVP+Kp1QvBDa5Bdg7ESiy8YBae2+55FqXsb8nXjsqqbwFWDA== +"@budibase/pouchdb-replication-stream@1.2.10": + version "1.2.10" + resolved "https://registry.yarnpkg.com/@budibase/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.10.tgz#4100df2effd7c823edadddcdbdc380f6827eebf5" + integrity sha512-1zeorOwbelZ7HF5vFB+pKE8Mnh31om8k1M6T3AZXVULYTHLsyJrMTozSv5CJ1P8ZfOIJab09HDzCXDh2icFekg== dependencies: - "@budibase/backend-core" "2.3.16" - "@budibase/types" "2.3.16" + argsarray "0.0.1" + inherits "^2.0.3" + lodash.pick "^4.0.0" + ndjson "^1.4.3" + pouch-stream "^0.4.0" + pouchdb-promise "^6.0.4" + through2 "^2.0.0" + +"@budibase/pro@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.0.tgz#85d832e00801eb2fd20242a4250559672a300611" + integrity sha512-sR4FEys8ypKwX66rhth2XJq5pi6KKSrRBScv1JtB3XhJRjSTGjRPKFuXNR23B+wNZ9jonIyS8pEv38Qn+zO3Gg== + dependencies: + "@budibase/backend-core" "2.3.17-alpha.0" + "@budibase/types" "2.3.17-alpha.0" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1411,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.16", "@budibase/types@^2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.16.tgz#6d94b5f34ca58bcca1cca45737d0d1d0b21c9413" - integrity sha512-7caUKOlhleQL5gRqcgxSWvHcWIbl8hRPFl5ttWlLTfGO7BDMIRrcW7Wmptmgzoc6MiNCQAQ/uuZ8DeVOlJKRBA== +"@budibase/types@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.0.tgz#4f60bedd7b2b54695c5ed2abd7025efd016d9bff" + integrity sha512-FBhV50D7Xsixz2DPBShu/iedcOtsm0QPHhWDWO6SSrXYe7pU0tgnIbBfwgwEWgqXlR3BRMHfEh9mmUiHew7ORA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 817fca19c3..d38c16bf39 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.0", - "@budibase/pro": "2.3.16", + "@budibase/pro": "2.3.17-alpha.0", "@budibase/string-templates": "2.3.17-alpha.0", "@budibase/types": "2.3.17-alpha.0", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index d1f13b4d46..bab10c36ba 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,13 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.16.tgz#05a8434501718b9eab0109be03c677c1d546fe17" - integrity sha512-wMuqxKVua3/3XejUMH/fJQgu1kK6t4HYpB5AY58sumNSLbFFp1MyqL+1LMSmpUY0nbjExq+9+wseNsnbWicWUw== +"@budibase/backend-core@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.0.tgz#3a4e9323e9a057af0fdbdfe72c570eeec1c154ff" + integrity sha512-zxbxcmcgP7chm9Vt5Scbvegg482KXPhJTXjF2g8/06MPSPnwHkUGreUpH25X7Jei5OUGKlG89BonAhmyRBGErg== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.16" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.17-alpha.0" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -506,7 +507,6 @@ posthog-node "1.3.0" pouchdb "7.3.0" pouchdb-find "7.2.2" - pouchdb-replication-stream "1.2.9" redlock "4.2.0" sanitize-s3-objectkey "0.0.1" semver "7.3.7" @@ -526,13 +526,26 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.16.tgz#3eca93b826ed6da5b6941d8b384c34c57da2b1b4" - integrity sha512-lIbPXOs61WP7jE80XHRDkBRmSEMYjiaog+qw0dUVP+Kp1QvBDa5Bdg7ESiy8YBae2+55FqXsb8nXjsqqbwFWDA== +"@budibase/pouchdb-replication-stream@1.2.10": + version "1.2.10" + resolved "https://registry.yarnpkg.com/@budibase/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.10.tgz#4100df2effd7c823edadddcdbdc380f6827eebf5" + integrity sha512-1zeorOwbelZ7HF5vFB+pKE8Mnh31om8k1M6T3AZXVULYTHLsyJrMTozSv5CJ1P8ZfOIJab09HDzCXDh2icFekg== dependencies: - "@budibase/backend-core" "2.3.16" - "@budibase/types" "2.3.16" + argsarray "0.0.1" + inherits "^2.0.3" + lodash.pick "^4.0.0" + ndjson "^1.4.3" + pouch-stream "^0.4.0" + pouchdb-promise "^6.0.4" + through2 "^2.0.0" + +"@budibase/pro@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.0.tgz#85d832e00801eb2fd20242a4250559672a300611" + integrity sha512-sR4FEys8ypKwX66rhth2XJq5pi6KKSrRBScv1JtB3XhJRjSTGjRPKFuXNR23B+wNZ9jonIyS8pEv38Qn+zO3Gg== + dependencies: + "@budibase/backend-core" "2.3.17-alpha.0" + "@budibase/types" "2.3.17-alpha.0" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -540,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.16", "@budibase/types@^2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.16.tgz#6d94b5f34ca58bcca1cca45737d0d1d0b21c9413" - integrity sha512-7caUKOlhleQL5gRqcgxSWvHcWIbl8hRPFl5ttWlLTfGO7BDMIRrcW7Wmptmgzoc6MiNCQAQ/uuZ8DeVOlJKRBA== +"@budibase/types@2.3.17-alpha.0": + version "2.3.17-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.0.tgz#4f60bedd7b2b54695c5ed2abd7025efd016d9bff" + integrity sha512-FBhV50D7Xsixz2DPBShu/iedcOtsm0QPHhWDWO6SSrXYe7pU0tgnIbBfwgwEWgqXlR3BRMHfEh9mmUiHew7ORA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -6768,19 +6781,6 @@ pouchdb-promise@6.4.3, pouchdb-promise@^6.0.4: dependencies: lie "3.1.1" -pouchdb-replication-stream@1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.9.tgz#aa4fa5d8f52df4825392f18e07c7e11acffc650a" - integrity sha512-hM8XRBfamTTUwRhKwLS/jSNouBhn9R/4ugdHNRD1EvJzwV8iImh6sDYbCU9PGuznjyOjXz6vpFRzKeI2KYfwnQ== - dependencies: - argsarray "0.0.1" - inherits "^2.0.3" - lodash.pick "^4.0.0" - ndjson "^1.4.3" - pouch-stream "^0.4.0" - pouchdb-promise "^6.0.4" - through2 "^2.0.0" - pouchdb-selector-core@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz#264d7436a8c8ac3801f39960e79875ef7f3879a0" From 8fe0cdf89f1ca3012f276c95704413b4f9936796 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Thu, 16 Feb 2023 16:23:44 +0000 Subject: [PATCH 027/273] Handle webhook errors (#9715) --- .../server/src/automations/steps/discord.ts | 38 +++++++++++----- .../src/automations/steps/integromat.ts | 42 ++++++++++++------ .../server/src/automations/steps/slack.ts | 34 ++++++++++---- .../server/src/automations/steps/zapier.ts | 44 +++++++++++++------ 4 files changed, 111 insertions(+), 47 deletions(-) diff --git a/packages/server/src/automations/steps/discord.ts b/packages/server/src/automations/steps/discord.ts index ae484fa42e..5d7487ed3b 100644 --- a/packages/server/src/automations/steps/discord.ts +++ b/packages/server/src/automations/steps/discord.ts @@ -67,17 +67,33 @@ export async function run({ inputs }: AutomationStepInput) { if (!avatar_url) { avatar_url = DEFAULT_AVATAR_URL } - const response = await fetch(url, { - method: "post", - body: JSON.stringify({ - username, - avatar_url, - content, - }), - headers: { - "Content-Type": "application/json", - }, - }) + if (!url?.trim()?.length) { + return { + httpStatus: 400, + response: "Missing Webhook URL", + success: false, + } + } + let response + try { + response = await fetch(url, { + method: "post", + body: JSON.stringify({ + username, + avatar_url, + content, + }), + headers: { + "Content-Type": "application/json", + }, + }) + } catch (err: any) { + return { + httpStatus: 400, + response: err.message, + success: false, + } + } const { status, message } = await getFetchResponse(response) return { diff --git a/packages/server/src/automations/steps/integromat.ts b/packages/server/src/automations/steps/integromat.ts index dd897b5429..811c0a3d91 100644 --- a/packages/server/src/automations/steps/integromat.ts +++ b/packages/server/src/automations/steps/integromat.ts @@ -69,19 +69,35 @@ export const definition: AutomationStepSchema = { export async function run({ inputs }: AutomationStepInput) { const { url, value1, value2, value3, value4, value5 } = inputs - const response = await fetch(url, { - method: "post", - body: JSON.stringify({ - value1, - value2, - value3, - value4, - value5, - }), - headers: { - "Content-Type": "application/json", - }, - }) + if (!url?.trim()?.length) { + return { + httpStatus: 400, + response: "Missing Webhook URL", + success: false, + } + } + let response + try { + response = await fetch(url, { + method: "post", + body: JSON.stringify({ + value1, + value2, + value3, + value4, + value5, + }), + headers: { + "Content-Type": "application/json", + }, + }) + } catch (err: any) { + return { + httpStatus: 400, + response: err.message, + success: false, + } + } const { status, message } = await getFetchResponse(response) return { diff --git a/packages/server/src/automations/steps/slack.ts b/packages/server/src/automations/steps/slack.ts index 47c66bebf3..0c9320a699 100644 --- a/packages/server/src/automations/steps/slack.ts +++ b/packages/server/src/automations/steps/slack.ts @@ -50,15 +50,31 @@ export const definition: AutomationStepSchema = { export async function run({ inputs }: AutomationStepInput) { let { url, text } = inputs - const response = await fetch(url, { - method: "post", - body: JSON.stringify({ - text, - }), - headers: { - "Content-Type": "application/json", - }, - }) + if (!url?.trim()?.length) { + return { + httpStatus: 400, + response: "Missing Webhook URL", + success: false, + } + } + let response + try { + response = await fetch(url, { + method: "post", + body: JSON.stringify({ + text, + }), + headers: { + "Content-Type": "application/json", + }, + }) + } catch (err: any) { + return { + httpStatus: 400, + response: err.message, + success: false, + } + } const { status, message } = await getFetchResponse(response) return { diff --git a/packages/server/src/automations/steps/zapier.ts b/packages/server/src/automations/steps/zapier.ts index 1a48c1ec92..90068e685d 100644 --- a/packages/server/src/automations/steps/zapier.ts +++ b/packages/server/src/automations/steps/zapier.ts @@ -63,22 +63,38 @@ export const definition: AutomationStepSchema = { export async function run({ inputs }: AutomationStepInput) { const { url, value1, value2, value3, value4, value5 } = inputs + if (!url?.trim()?.length) { + return { + httpStatus: 400, + response: "Missing Webhook URL", + success: false, + } + } // send the platform to make sure zaps always work, even // if no values supplied - const response = await fetch(url, { - method: "post", - body: JSON.stringify({ - platform: "budibase", - value1, - value2, - value3, - value4, - value5, - }), - headers: { - "Content-Type": "application/json", - }, - }) + let response + try { + response = await fetch(url, { + method: "post", + body: JSON.stringify({ + platform: "budibase", + value1, + value2, + value3, + value4, + value5, + }), + headers: { + "Content-Type": "application/json", + }, + }) + } catch (err: any) { + return { + httpStatus: 400, + response: err.message, + success: false, + } + } const { status, message } = await getFetchResponse(response) From cd0e7d41a590a91efa66100ccded842c49f7b519 Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Thu, 16 Feb 2023 16:37:12 +0000 Subject: [PATCH 028/273] v2.3.17 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 0377c73101..cfbed56e23 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.16", + "version": "2.3.17", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 455436ff6a..25e73b9e4d 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.16", + "version": "2.3.17", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -23,7 +23,7 @@ }, "dependencies": { "@budibase/nano": "10.1.1", - "@budibase/types": "^2.3.16", + "@budibase/types": "^2.3.17", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 073f57f094..8c9629b314 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.16", + "version": "2.3.17", "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.3.16", + "@budibase/string-templates": "^2.3.17", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 7def4ba371..5e968c23a3 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.16", + "version": "2.3.17", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "^2.3.16", - "@budibase/client": "^2.3.16", - "@budibase/frontend-core": "^2.3.16", - "@budibase/string-templates": "^2.3.16", + "@budibase/bbui": "^2.3.17", + "@budibase/client": "^2.3.17", + "@budibase/frontend-core": "^2.3.17", + "@budibase/string-templates": "^2.3.17", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 5209c51b2e..fb08c290fc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.16", + "version": "2.3.17", "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.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/backend-core": "^2.3.17", + "@budibase/string-templates": "^2.3.17", + "@budibase/types": "^2.3.17", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 5e2dad5217..78df2b67f7 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.16", + "version": "2.3.17", "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.3.16", - "@budibase/frontend-core": "^2.3.16", - "@budibase/string-templates": "^2.3.16", + "@budibase/bbui": "^2.3.17", + "@budibase/frontend-core": "^2.3.17", + "@budibase/string-templates": "^2.3.17", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 897b7107cf..502df0fbd4 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.16", + "version": "2.3.17", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^2.3.16", + "@budibase/bbui": "^2.3.17", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 51f5ca70e0..d8a5c44c5b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.16", + "version": "2.3.17", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index aec1e3d047..78f03e0bfe 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.16", + "version": "2.3.17", "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.3.16", - "@budibase/client": "^2.3.16", + "@budibase/backend-core": "^2.3.17", + "@budibase/client": "^2.3.17", "@budibase/pro": "2.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/string-templates": "^2.3.17", + "@budibase/types": "^2.3.17", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 6b99e321e5..87b7c69dbb 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.16", + "version": "2.3.17", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 7d679edcf6..8417cadc06 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.16", + "version": "2.3.17", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 7c2518e8b5..a146e431c2 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.16", + "version": "2.3.17", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^2.3.16", + "@budibase/backend-core": "^2.3.17", "@budibase/pro": "2.3.16", - "@budibase/string-templates": "^2.3.16", - "@budibase/types": "^2.3.16", + "@budibase/string-templates": "^2.3.17", + "@budibase/types": "^2.3.17", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 580822f4a8427048a5c4475f6424d778b0e2e06e Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Thu, 16 Feb 2023 16:41:23 +0000 Subject: [PATCH 029/273] Update pro version to 2.3.17 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 78f03e0bfe..f5787302fe 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "^2.3.17", "@budibase/client": "^2.3.17", - "@budibase/pro": "2.3.16", + "@budibase/pro": "2.3.17", "@budibase/string-templates": "^2.3.17", "@budibase/types": "^2.3.17", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index e88dfaf333..31a5b3350e 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1273,13 +1273,13 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.16.tgz#05a8434501718b9eab0109be03c677c1d546fe17" - integrity sha512-wMuqxKVua3/3XejUMH/fJQgu1kK6t4HYpB5AY58sumNSLbFFp1MyqL+1LMSmpUY0nbjExq+9+wseNsnbWicWUw== +"@budibase/backend-core@2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17.tgz#27c8c2144bfda1533b43da6de7111c0819aea6a5" + integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.16" + "@budibase/types" "^2.3.17" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1374,13 +1374,13 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.16.tgz#3eca93b826ed6da5b6941d8b384c34c57da2b1b4" - integrity sha512-lIbPXOs61WP7jE80XHRDkBRmSEMYjiaog+qw0dUVP+Kp1QvBDa5Bdg7ESiy8YBae2+55FqXsb8nXjsqqbwFWDA== +"@budibase/pro@2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17.tgz#1a05d3d13195fcfacac410305fcd0943fbbcd5c8" + integrity sha512-sdWuKRDbseu2POkyGfmiqAWp8M9jGmpD0FqaIEWGQmKdezvOKh3sGg0PGT4InoibbXcFf4vVB+HiofBedDFLkA== dependencies: - "@budibase/backend-core" "2.3.16" - "@budibase/types" "2.3.16" + "@budibase/backend-core" "2.3.17" + "@budibase/types" "2.3.17" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1406,10 +1406,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.16", "@budibase/types@^2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.16.tgz#6d94b5f34ca58bcca1cca45737d0d1d0b21c9413" - integrity sha512-7caUKOlhleQL5gRqcgxSWvHcWIbl8hRPFl5ttWlLTfGO7BDMIRrcW7Wmptmgzoc6MiNCQAQ/uuZ8DeVOlJKRBA== +"@budibase/types@2.3.17", "@budibase/types@^2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17.tgz#d97c1de5fb03c91ff7e55d7c8c3901e5e2e95995" + integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index a146e431c2..71b8ed6e9c 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "^2.3.17", - "@budibase/pro": "2.3.16", + "@budibase/pro": "2.3.17", "@budibase/string-templates": "^2.3.17", "@budibase/types": "^2.3.17", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 826a6bd680..43d5ffb1bd 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -470,13 +470,13 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.16.tgz#05a8434501718b9eab0109be03c677c1d546fe17" - integrity sha512-wMuqxKVua3/3XejUMH/fJQgu1kK6t4HYpB5AY58sumNSLbFFp1MyqL+1LMSmpUY0nbjExq+9+wseNsnbWicWUw== +"@budibase/backend-core@2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17.tgz#27c8c2144bfda1533b43da6de7111c0819aea6a5" + integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.16" + "@budibase/types" "^2.3.17" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -521,13 +521,13 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.16.tgz#3eca93b826ed6da5b6941d8b384c34c57da2b1b4" - integrity sha512-lIbPXOs61WP7jE80XHRDkBRmSEMYjiaog+qw0dUVP+Kp1QvBDa5Bdg7ESiy8YBae2+55FqXsb8nXjsqqbwFWDA== +"@budibase/pro@2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17.tgz#1a05d3d13195fcfacac410305fcd0943fbbcd5c8" + integrity sha512-sdWuKRDbseu2POkyGfmiqAWp8M9jGmpD0FqaIEWGQmKdezvOKh3sGg0PGT4InoibbXcFf4vVB+HiofBedDFLkA== dependencies: - "@budibase/backend-core" "2.3.16" - "@budibase/types" "2.3.16" + "@budibase/backend-core" "2.3.17" + "@budibase/types" "2.3.17" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -535,10 +535,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.16", "@budibase/types@^2.3.16": - version "2.3.16" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.16.tgz#6d94b5f34ca58bcca1cca45737d0d1d0b21c9413" - integrity sha512-7caUKOlhleQL5gRqcgxSWvHcWIbl8hRPFl5ttWlLTfGO7BDMIRrcW7Wmptmgzoc6MiNCQAQ/uuZ8DeVOlJKRBA== +"@budibase/types@2.3.17", "@budibase/types@^2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17.tgz#d97c1de5fb03c91ff7e55d7c8c3901e5e2e95995" + integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 49d9539c529efa12a5a48da9fa8a453bf6f1fc35 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Thu, 16 Feb 2023 16:44:50 +0000 Subject: [PATCH 030/273] Fix server docker build (#9718) --- packages/server/tsconfig.build.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/tsconfig.build.json b/packages/server/tsconfig.build.json index 212fc1479d..9289b6f9da 100644 --- a/packages/server/tsconfig.build.json +++ b/packages/server/tsconfig.build.json @@ -20,6 +20,7 @@ "dist", "src/tests", "src/api/routes/tests/utilities", + "src/api/routes/public/tests/utils.ts", "src/automations/tests/utilities", "**/*.spec.ts", "**/*.spec.js" From 788a9129334e66ff8270369051f78d7c6cdf1ad9 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 16 Feb 2023 16:52:04 +0000 Subject: [PATCH 031/273] v2.3.17-alpha.1 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 2ecb0c19a5..658bded52f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 754dfe197f..2c63a821e8 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.0", + "@budibase/types": "2.3.17-alpha.1", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 68da2f91d1..d78388fcec 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "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.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.1", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index ed700b1397..60c933aa24 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.0", - "@budibase/client": "2.3.17-alpha.0", - "@budibase/frontend-core": "2.3.17-alpha.0", - "@budibase/string-templates": "2.3.17-alpha.0", + "@budibase/bbui": "2.3.17-alpha.1", + "@budibase/client": "2.3.17-alpha.1", + "@budibase/frontend-core": "2.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.1", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index badd55fad8..4af1c43cf4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "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.3.17-alpha.0", - "@budibase/string-templates": "2.3.17-alpha.0", - "@budibase/types": "2.3.17-alpha.0", + "@budibase/backend-core": "2.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.1", + "@budibase/types": "2.3.17-alpha.1", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 1b5c3708ad..13684f4d43 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "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.3.17-alpha.0", - "@budibase/frontend-core": "2.3.17-alpha.0", - "@budibase/string-templates": "2.3.17-alpha.0", + "@budibase/bbui": "2.3.17-alpha.1", + "@budibase/frontend-core": "2.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.1", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 94b8e1dcdd..f76fa2c3fe 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.0", + "@budibase/bbui": "2.3.17-alpha.1", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index ca166434d4..f8b3d2544e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 219ac04de2..9c0f16b62f 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "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.3.17-alpha.0", - "@budibase/client": "2.3.17-alpha.0", + "@budibase/backend-core": "2.3.17-alpha.1", + "@budibase/client": "2.3.17-alpha.1", "@budibase/pro": "2.3.17-alpha.0", - "@budibase/string-templates": "2.3.17-alpha.0", - "@budibase/types": "2.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.1", + "@budibase/types": "2.3.17-alpha.1", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 3445666e3a..7dece7ded5 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 8c1c6f588a..3a0653632d 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index d38c16bf39..a930af1e12 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.0", + "version": "2.3.17-alpha.1", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.0", + "@budibase/backend-core": "2.3.17-alpha.1", "@budibase/pro": "2.3.17-alpha.0", - "@budibase/string-templates": "2.3.17-alpha.0", - "@budibase/types": "2.3.17-alpha.0", + "@budibase/string-templates": "2.3.17-alpha.1", + "@budibase/types": "2.3.17-alpha.1", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 457a60bff8e4afa204c88b40720b80e7265dbe60 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 16 Feb 2023 16:56:11 +0000 Subject: [PATCH 032/273] Update pro version to 2.3.17-alpha.1 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 9c0f16b62f..a4c9c119f1 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.1", "@budibase/client": "2.3.17-alpha.1", - "@budibase/pro": "2.3.17-alpha.0", + "@budibase/pro": "2.3.17-alpha.1", "@budibase/string-templates": "2.3.17-alpha.1", "@budibase/types": "2.3.17-alpha.1", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 5c0e299c3a..2465c4f498 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.0.tgz#3a4e9323e9a057af0fdbdfe72c570eeec1c154ff" - integrity sha512-zxbxcmcgP7chm9Vt5Scbvegg482KXPhJTXjF2g8/06MPSPnwHkUGreUpH25X7Jei5OUGKlG89BonAhmyRBGErg== +"@budibase/backend-core@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.1.tgz#84bca579947d0369ef0cb50e86db8d182bfa48ff" + integrity sha512-yPU3DLD4JAaEtnBxxMZZUT/DDdy6vNAhKkW0t65NXLSXgqIii5JLi89TR0BbDXFNdSYAww+ashDXWbw7GhH7ng== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.0" + "@budibase/types" "2.3.17-alpha.1" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.0.tgz#85d832e00801eb2fd20242a4250559672a300611" - integrity sha512-sR4FEys8ypKwX66rhth2XJq5pi6KKSrRBScv1JtB3XhJRjSTGjRPKFuXNR23B+wNZ9jonIyS8pEv38Qn+zO3Gg== +"@budibase/pro@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.1.tgz#348b5d98772b50240b51e0d14070b9a9ec793527" + integrity sha512-l4vmhqHwJ3Zi+EperCbWE7vj1/CL2+eZHKgUMgmQ7WORmzXPW2rubZW+kf9UBsr9TQ7ynewPg/CQF/N8eDtXOw== dependencies: - "@budibase/backend-core" "2.3.17-alpha.0" - "@budibase/types" "2.3.17-alpha.0" + "@budibase/backend-core" "2.3.17-alpha.1" + "@budibase/types" "2.3.17-alpha.1" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.0.tgz#4f60bedd7b2b54695c5ed2abd7025efd016d9bff" - integrity sha512-FBhV50D7Xsixz2DPBShu/iedcOtsm0QPHhWDWO6SSrXYe7pU0tgnIbBfwgwEWgqXlR3BRMHfEh9mmUiHew7ORA== +"@budibase/types@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.1.tgz#c11a2bb579e31b5b10f168fbd09fc4244d2f0590" + integrity sha512-zpo9sH1TFNUY6MEWSKBLM5qmXc9NwoVl2HMZ01UOL7etXOR2cb2H9T5/DCX3rpCGVeWjf8zmvQXXAWhSIjLiPg== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index a930af1e12..237ff94535 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.1", - "@budibase/pro": "2.3.17-alpha.0", + "@budibase/pro": "2.3.17-alpha.1", "@budibase/string-templates": "2.3.17-alpha.1", "@budibase/types": "2.3.17-alpha.1", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index bab10c36ba..7b67ba7ca9 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.0.tgz#3a4e9323e9a057af0fdbdfe72c570eeec1c154ff" - integrity sha512-zxbxcmcgP7chm9Vt5Scbvegg482KXPhJTXjF2g8/06MPSPnwHkUGreUpH25X7Jei5OUGKlG89BonAhmyRBGErg== +"@budibase/backend-core@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.1.tgz#84bca579947d0369ef0cb50e86db8d182bfa48ff" + integrity sha512-yPU3DLD4JAaEtnBxxMZZUT/DDdy6vNAhKkW0t65NXLSXgqIii5JLi89TR0BbDXFNdSYAww+ashDXWbw7GhH7ng== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.0" + "@budibase/types" "2.3.17-alpha.1" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.0.tgz#85d832e00801eb2fd20242a4250559672a300611" - integrity sha512-sR4FEys8ypKwX66rhth2XJq5pi6KKSrRBScv1JtB3XhJRjSTGjRPKFuXNR23B+wNZ9jonIyS8pEv38Qn+zO3Gg== +"@budibase/pro@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.1.tgz#348b5d98772b50240b51e0d14070b9a9ec793527" + integrity sha512-l4vmhqHwJ3Zi+EperCbWE7vj1/CL2+eZHKgUMgmQ7WORmzXPW2rubZW+kf9UBsr9TQ7ynewPg/CQF/N8eDtXOw== dependencies: - "@budibase/backend-core" "2.3.17-alpha.0" - "@budibase/types" "2.3.17-alpha.0" + "@budibase/backend-core" "2.3.17-alpha.1" + "@budibase/types" "2.3.17-alpha.1" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.0": - version "2.3.17-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.0.tgz#4f60bedd7b2b54695c5ed2abd7025efd016d9bff" - integrity sha512-FBhV50D7Xsixz2DPBShu/iedcOtsm0QPHhWDWO6SSrXYe7pU0tgnIbBfwgwEWgqXlR3BRMHfEh9mmUiHew7ORA== +"@budibase/types@2.3.17-alpha.1": + version "2.3.17-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.1.tgz#c11a2bb579e31b5b10f168fbd09fc4244d2f0590" + integrity sha512-zpo9sH1TFNUY6MEWSKBLM5qmXc9NwoVl2HMZ01UOL7etXOR2cb2H9T5/DCX3rpCGVeWjf8zmvQXXAWhSIjLiPg== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From eb6b49d84328830632726d88c7a961928d6d38df Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Fri, 17 Feb 2023 08:25:10 +0000 Subject: [PATCH 033/273] Fix qa deploy dispatch (#9724) --- .github/workflows/release-develop.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-develop.yml b/.github/workflows/release-develop.yml index d679d31139..16c6c37bbd 100644 --- a/.github/workflows/release-develop.yml +++ b/.github/workflows/release-develop.yml @@ -193,5 +193,5 @@ jobs: PAYLOAD_VERSION: ${{ env.RELEASE_VERSION }} with: repository: budibase/budibase-deploys - event: deploy-budibase-develop-to-qa + event: budicloud-qa-deploy github_pat: ${{ secrets.GH_ACCESS_TOKEN }} \ No newline at end of file From 74c7a23c5c85441b8839d9b5b4617b5eb698daf1 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 17 Feb 2023 08:32:08 +0000 Subject: [PATCH 034/273] v2.3.17-alpha.2 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 658bded52f..ed684ccd66 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 2c63a821e8..1805a07a09 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.1", + "@budibase/types": "2.3.17-alpha.2", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index d78388fcec..09c199d0f3 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "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.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.2", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 60c933aa24..54fa2e6f7c 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.1", - "@budibase/client": "2.3.17-alpha.1", - "@budibase/frontend-core": "2.3.17-alpha.1", - "@budibase/string-templates": "2.3.17-alpha.1", + "@budibase/bbui": "2.3.17-alpha.2", + "@budibase/client": "2.3.17-alpha.2", + "@budibase/frontend-core": "2.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.2", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 4af1c43cf4..610d617a0e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "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.3.17-alpha.1", - "@budibase/string-templates": "2.3.17-alpha.1", - "@budibase/types": "2.3.17-alpha.1", + "@budibase/backend-core": "2.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.2", + "@budibase/types": "2.3.17-alpha.2", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 13684f4d43..65dbb25abf 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "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.3.17-alpha.1", - "@budibase/frontend-core": "2.3.17-alpha.1", - "@budibase/string-templates": "2.3.17-alpha.1", + "@budibase/bbui": "2.3.17-alpha.2", + "@budibase/frontend-core": "2.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.2", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index f76fa2c3fe..89dd18fc02 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.1", + "@budibase/bbui": "2.3.17-alpha.2", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index f8b3d2544e..828fb83423 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index a4c9c119f1..f5a2aba821 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "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.3.17-alpha.1", - "@budibase/client": "2.3.17-alpha.1", + "@budibase/backend-core": "2.3.17-alpha.2", + "@budibase/client": "2.3.17-alpha.2", "@budibase/pro": "2.3.17-alpha.1", - "@budibase/string-templates": "2.3.17-alpha.1", - "@budibase/types": "2.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.2", + "@budibase/types": "2.3.17-alpha.2", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 7dece7ded5..10976112d9 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 3a0653632d..0c7f4e6b2b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 237ff94535..605fa2ec17 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.1", + "version": "2.3.17-alpha.2", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.1", + "@budibase/backend-core": "2.3.17-alpha.2", "@budibase/pro": "2.3.17-alpha.1", - "@budibase/string-templates": "2.3.17-alpha.1", - "@budibase/types": "2.3.17-alpha.1", + "@budibase/string-templates": "2.3.17-alpha.2", + "@budibase/types": "2.3.17-alpha.2", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 8971a14865ec1611053290c4037a078b876d161b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 17 Feb 2023 08:36:00 +0000 Subject: [PATCH 035/273] Update pro version to 2.3.17-alpha.2 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index f5a2aba821..eb543ac488 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.2", "@budibase/client": "2.3.17-alpha.2", - "@budibase/pro": "2.3.17-alpha.1", + "@budibase/pro": "2.3.17-alpha.2", "@budibase/string-templates": "2.3.17-alpha.2", "@budibase/types": "2.3.17-alpha.2", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 2465c4f498..a850816b1b 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.1.tgz#84bca579947d0369ef0cb50e86db8d182bfa48ff" - integrity sha512-yPU3DLD4JAaEtnBxxMZZUT/DDdy6vNAhKkW0t65NXLSXgqIii5JLi89TR0BbDXFNdSYAww+ashDXWbw7GhH7ng== +"@budibase/backend-core@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.2.tgz#f8c7f06ee63e59149590143867a721f3ea2d3fb0" + integrity sha512-4IUilkKl1zBjVVe/cqSA+Wm8z7Dq+vNwVJxaxoSEEr0Vs+OaNi31LTO5ji4Vt5qinwmutvUorbP27tjrFuRauw== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.1" + "@budibase/types" "2.3.17-alpha.2" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.1.tgz#348b5d98772b50240b51e0d14070b9a9ec793527" - integrity sha512-l4vmhqHwJ3Zi+EperCbWE7vj1/CL2+eZHKgUMgmQ7WORmzXPW2rubZW+kf9UBsr9TQ7ynewPg/CQF/N8eDtXOw== +"@budibase/pro@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.2.tgz#e382819c0b3ef9ecfd660cd492bd9410a7dbe46a" + integrity sha512-AzoiLg1dQJD6MEka1eQLdYts0HG6ztVyrt7nl1xVNyFSg++rBrZ51kNulv32104ASOQ0TJfULvbZf13POkCxdQ== dependencies: - "@budibase/backend-core" "2.3.17-alpha.1" - "@budibase/types" "2.3.17-alpha.1" + "@budibase/backend-core" "2.3.17-alpha.2" + "@budibase/types" "2.3.17-alpha.2" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.1.tgz#c11a2bb579e31b5b10f168fbd09fc4244d2f0590" - integrity sha512-zpo9sH1TFNUY6MEWSKBLM5qmXc9NwoVl2HMZ01UOL7etXOR2cb2H9T5/DCX3rpCGVeWjf8zmvQXXAWhSIjLiPg== +"@budibase/types@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.2.tgz#9b0d13b7a20951003ef84a99fbcb2650d7a9e5cc" + integrity sha512-VEECoGPuAY2ajgDcsUTzvaWZlWVwzprK58WnhnZdnhGLqtB4Fd6eGjGPecWA4l4RWEmg5FMy66M5mHAUC0KG7w== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 605fa2ec17..5aa6982372 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.2", - "@budibase/pro": "2.3.17-alpha.1", + "@budibase/pro": "2.3.17-alpha.2", "@budibase/string-templates": "2.3.17-alpha.2", "@budibase/types": "2.3.17-alpha.2", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 7b67ba7ca9..766b5337f2 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.1.tgz#84bca579947d0369ef0cb50e86db8d182bfa48ff" - integrity sha512-yPU3DLD4JAaEtnBxxMZZUT/DDdy6vNAhKkW0t65NXLSXgqIii5JLi89TR0BbDXFNdSYAww+ashDXWbw7GhH7ng== +"@budibase/backend-core@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.2.tgz#f8c7f06ee63e59149590143867a721f3ea2d3fb0" + integrity sha512-4IUilkKl1zBjVVe/cqSA+Wm8z7Dq+vNwVJxaxoSEEr0Vs+OaNi31LTO5ji4Vt5qinwmutvUorbP27tjrFuRauw== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.1" + "@budibase/types" "2.3.17-alpha.2" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.1.tgz#348b5d98772b50240b51e0d14070b9a9ec793527" - integrity sha512-l4vmhqHwJ3Zi+EperCbWE7vj1/CL2+eZHKgUMgmQ7WORmzXPW2rubZW+kf9UBsr9TQ7ynewPg/CQF/N8eDtXOw== +"@budibase/pro@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.2.tgz#e382819c0b3ef9ecfd660cd492bd9410a7dbe46a" + integrity sha512-AzoiLg1dQJD6MEka1eQLdYts0HG6ztVyrt7nl1xVNyFSg++rBrZ51kNulv32104ASOQ0TJfULvbZf13POkCxdQ== dependencies: - "@budibase/backend-core" "2.3.17-alpha.1" - "@budibase/types" "2.3.17-alpha.1" + "@budibase/backend-core" "2.3.17-alpha.2" + "@budibase/types" "2.3.17-alpha.2" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.1": - version "2.3.17-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.1.tgz#c11a2bb579e31b5b10f168fbd09fc4244d2f0590" - integrity sha512-zpo9sH1TFNUY6MEWSKBLM5qmXc9NwoVl2HMZ01UOL7etXOR2cb2H9T5/DCX3rpCGVeWjf8zmvQXXAWhSIjLiPg== +"@budibase/types@2.3.17-alpha.2": + version "2.3.17-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.2.tgz#9b0d13b7a20951003ef84a99fbcb2650d7a9e5cc" + integrity sha512-VEECoGPuAY2ajgDcsUTzvaWZlWVwzprK58WnhnZdnhGLqtB4Fd6eGjGPecWA4l4RWEmg5FMy66M5mHAUC0KG7w== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From b34b5fc5bb9399f65902bcada459aca5ffffb047 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Fri, 17 Feb 2023 09:16:11 +0000 Subject: [PATCH 036/273] Fix tenant creation on user save (#9725) --- packages/worker/src/sdk/users/users.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 8410d0b2e0..5124a5c5b1 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -264,6 +264,7 @@ export const save = async ( builtUser._rev = response.rev await eventHelpers.handleSaveEvents(builtUser, dbUser) + await addTenant(tenantId, _id, email) await cache.user.invalidateUser(response.id) // let server know to sync user From 1ad2f46766a9b9cb4fe5e454ace37926e47dc685 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 17 Feb 2023 09:25:55 +0000 Subject: [PATCH 037/273] v2.3.17-alpha.3 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index ed684ccd66..01e2e63d21 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 1805a07a09..66cbecaaa2 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.2", + "@budibase/types": "2.3.17-alpha.3", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 09c199d0f3..b5407ade15 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "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.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.3", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 54fa2e6f7c..baee82d246 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.2", - "@budibase/client": "2.3.17-alpha.2", - "@budibase/frontend-core": "2.3.17-alpha.2", - "@budibase/string-templates": "2.3.17-alpha.2", + "@budibase/bbui": "2.3.17-alpha.3", + "@budibase/client": "2.3.17-alpha.3", + "@budibase/frontend-core": "2.3.17-alpha.3", + "@budibase/string-templates": "2.3.17-alpha.3", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 610d617a0e..61a05b728a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "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.3.17-alpha.2", - "@budibase/string-templates": "2.3.17-alpha.2", - "@budibase/types": "2.3.17-alpha.2", + "@budibase/backend-core": "2.3.17-alpha.3", + "@budibase/string-templates": "2.3.17-alpha.3", + "@budibase/types": "2.3.17-alpha.3", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 65dbb25abf..69dec984d2 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "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.3.17-alpha.2", - "@budibase/frontend-core": "2.3.17-alpha.2", - "@budibase/string-templates": "2.3.17-alpha.2", + "@budibase/bbui": "2.3.17-alpha.3", + "@budibase/frontend-core": "2.3.17-alpha.3", + "@budibase/string-templates": "2.3.17-alpha.3", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 89dd18fc02..53ad0ec7bf 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.2", + "@budibase/bbui": "2.3.17-alpha.3", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 828fb83423..1514665bc1 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index eb543ac488..38d78d61f6 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "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.3.17-alpha.2", - "@budibase/client": "2.3.17-alpha.2", + "@budibase/backend-core": "2.3.17-alpha.3", + "@budibase/client": "2.3.17-alpha.3", "@budibase/pro": "2.3.17-alpha.2", - "@budibase/string-templates": "2.3.17-alpha.2", - "@budibase/types": "2.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.3", + "@budibase/types": "2.3.17-alpha.3", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 10976112d9..6bd73b6587 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 0c7f4e6b2b..97fe50d854 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 5aa6982372..1d960cb970 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.2", + "version": "2.3.17-alpha.3", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.2", + "@budibase/backend-core": "2.3.17-alpha.3", "@budibase/pro": "2.3.17-alpha.2", - "@budibase/string-templates": "2.3.17-alpha.2", - "@budibase/types": "2.3.17-alpha.2", + "@budibase/string-templates": "2.3.17-alpha.3", + "@budibase/types": "2.3.17-alpha.3", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 0e0c3d9067a1a593708635604ea5373ef19f6ba4 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 17 Feb 2023 09:30:40 +0000 Subject: [PATCH 038/273] Update pro version to 2.3.17-alpha.3 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 38d78d61f6..e197139aee 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.3", "@budibase/client": "2.3.17-alpha.3", - "@budibase/pro": "2.3.17-alpha.2", + "@budibase/pro": "2.3.17-alpha.3", "@budibase/string-templates": "2.3.17-alpha.3", "@budibase/types": "2.3.17-alpha.3", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index a850816b1b..d244837785 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.2.tgz#f8c7f06ee63e59149590143867a721f3ea2d3fb0" - integrity sha512-4IUilkKl1zBjVVe/cqSA+Wm8z7Dq+vNwVJxaxoSEEr0Vs+OaNi31LTO5ji4Vt5qinwmutvUorbP27tjrFuRauw== +"@budibase/backend-core@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.3.tgz#9c30c40e0840931003ef696f7ea862c0fd1b5be4" + integrity sha512-dhMpC5ik/WxIxIqrX1tfeJbiCkvxtdIbHoMnbDhinDb9T+TA7IRbohalcCGhglvTC6zIi/5W7GYV7D/Uhwhf7w== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.2" + "@budibase/types" "2.3.17-alpha.3" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.2.tgz#e382819c0b3ef9ecfd660cd492bd9410a7dbe46a" - integrity sha512-AzoiLg1dQJD6MEka1eQLdYts0HG6ztVyrt7nl1xVNyFSg++rBrZ51kNulv32104ASOQ0TJfULvbZf13POkCxdQ== +"@budibase/pro@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.3.tgz#4b0a5a083baefdc93548d0fd177e36430ecd69f6" + integrity sha512-X9KcDXN82rveXgjvnLfWL06bQyDHICAqSb4EtSgmVElNxyfVKKznPoEPKYt3WlMTx7rlVaSEjvTna1Jb5pcuMA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.2" - "@budibase/types" "2.3.17-alpha.2" + "@budibase/backend-core" "2.3.17-alpha.3" + "@budibase/types" "2.3.17-alpha.3" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.2.tgz#9b0d13b7a20951003ef84a99fbcb2650d7a9e5cc" - integrity sha512-VEECoGPuAY2ajgDcsUTzvaWZlWVwzprK58WnhnZdnhGLqtB4Fd6eGjGPecWA4l4RWEmg5FMy66M5mHAUC0KG7w== +"@budibase/types@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.3.tgz#f490add0d9fc560177d429d1a1236dce16ded7fd" + integrity sha512-O1f5sBax377fpEMxkQYaeWp2odMUNIqxfl8aKE0XkczmfRpigjDrn27dOv+Uqlf/Qke0I8FA608yhV6fk3idTQ== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 1d960cb970..7de217fdd6 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.3", - "@budibase/pro": "2.3.17-alpha.2", + "@budibase/pro": "2.3.17-alpha.3", "@budibase/string-templates": "2.3.17-alpha.3", "@budibase/types": "2.3.17-alpha.3", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 766b5337f2..bc48f2cf5d 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.2.tgz#f8c7f06ee63e59149590143867a721f3ea2d3fb0" - integrity sha512-4IUilkKl1zBjVVe/cqSA+Wm8z7Dq+vNwVJxaxoSEEr0Vs+OaNi31LTO5ji4Vt5qinwmutvUorbP27tjrFuRauw== +"@budibase/backend-core@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.3.tgz#9c30c40e0840931003ef696f7ea862c0fd1b5be4" + integrity sha512-dhMpC5ik/WxIxIqrX1tfeJbiCkvxtdIbHoMnbDhinDb9T+TA7IRbohalcCGhglvTC6zIi/5W7GYV7D/Uhwhf7w== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.2" + "@budibase/types" "2.3.17-alpha.3" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.2.tgz#e382819c0b3ef9ecfd660cd492bd9410a7dbe46a" - integrity sha512-AzoiLg1dQJD6MEka1eQLdYts0HG6ztVyrt7nl1xVNyFSg++rBrZ51kNulv32104ASOQ0TJfULvbZf13POkCxdQ== +"@budibase/pro@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.3.tgz#4b0a5a083baefdc93548d0fd177e36430ecd69f6" + integrity sha512-X9KcDXN82rveXgjvnLfWL06bQyDHICAqSb4EtSgmVElNxyfVKKznPoEPKYt3WlMTx7rlVaSEjvTna1Jb5pcuMA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.2" - "@budibase/types" "2.3.17-alpha.2" + "@budibase/backend-core" "2.3.17-alpha.3" + "@budibase/types" "2.3.17-alpha.3" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.2": - version "2.3.17-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.2.tgz#9b0d13b7a20951003ef84a99fbcb2650d7a9e5cc" - integrity sha512-VEECoGPuAY2ajgDcsUTzvaWZlWVwzprK58WnhnZdnhGLqtB4Fd6eGjGPecWA4l4RWEmg5FMy66M5mHAUC0KG7w== +"@budibase/types@2.3.17-alpha.3": + version "2.3.17-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.3.tgz#f490add0d9fc560177d429d1a1236dce16ded7fd" + integrity sha512-O1f5sBax377fpEMxkQYaeWp2odMUNIqxfl8aKE0XkczmfRpigjDrn27dOv+Uqlf/Qke0I8FA608yhV6fk3idTQ== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 8289da3f19395df9d65c52a6f391a0542192e3ad Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Fri, 17 Feb 2023 14:49:35 +0000 Subject: [PATCH 039/273] Add Fetch Row Button Action (#9653) * Add Fetch Row Button Action * PR feedback --- .../actions/FetchRow.svelte | 40 +++++++++++++++++++ .../ButtonActionEditor/actions/index.js | 1 + .../controls/ButtonActionEditor/manifest.json | 13 +++++- packages/client/src/utils/buttonActions.js | 15 +++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/FetchRow.svelte diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/FetchRow.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/FetchRow.svelte new file mode 100644 index 0000000000..fb8b8c3f90 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/FetchRow.svelte @@ -0,0 +1,40 @@ + + +
+ + +
+ { + if (e.detail[0].length > 1) { + startDate = e.detail[0][0].toISOString() + endDate = e.detail[0][1].toISOString() + } + }} + />
app.appId} getOptionLabel={app => app.name} options={$apps} + bind:value={selectedApps} />
-
+
+ downloadLogs()} name="Download" /> +
+ +
@@ -171,30 +245,83 @@ {#if selectedLog} - -
hello
-
+
{ + sidePanelVisible = false + }} + > +
+ Audit Logs + { + sidePanelVisible = false + }} + /> +
+
+ +
+
{/if} diff --git a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte index 013d6b8ff4..cff578febd 100644 --- a/packages/builder/src/pages/builder/portal/settings/environment/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/environment/index.svelte @@ -55,7 +55,6 @@ notifications.error(`Error saving variable: ${err.message}`) } } - $: console.log($environment.variables) ({ */ searchAuditLogs: async opts => { return await API.post({ - url: `/api/auditlogs/search`, + url: `/api/global/auditlogs/search`, body: buildOpts(opts), }) }, getEventDefinitions: async () => { return await API.get({ - url: `/api/auditlogs/definitions`, + url: `/api/global/auditlogs/definitions`, }) }, downloadLogs: async opts => { return await API.post({ - url: `/api/auditlogs/definitions`, + url: `/api/global/auditlogs/definitions`, body: buildOpts(opts), }) }, From 0ee77aa9b0393d7feedc32a86a7b4989f47e2a3b Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Fri, 17 Feb 2023 17:27:17 +0000 Subject: [PATCH 044/273] adding test ci command to ignore local .env --- qa-core/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qa-core/package.json b/qa-core/package.json index 2ae04ece6c..7733e95d46 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -9,10 +9,11 @@ "url": "https://github.com/Budibase/budibase.git" }, "scripts": { - "test": "env-cmd jest --runInBand --json --outputFile=testResults.json", + "test": "env-cmd jest --runInBand", "test:watch": "env-cmd jest --watch", "test:debug": "DEBUG=1 jest", "test:notify": "node scripts/testResultsWebhook", + "test:ci": "jest --runInBand --json --outputFile=testResults.json", "docker:up": "docker-compose up -d", "docker:down": "docker-compose down", "api:server:setup": "npm run docker:up && env-cmd ts-node ../packages/builder/ts/setup.ts", From eca34d73edb091873f6deab0d8b9e7a3300c3186 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 17 Feb 2023 17:46:49 +0000 Subject: [PATCH 045/273] Finishing up search API, updating typing in lucene layer. --- packages/backend-core/src/db/lucene.ts | 72 +++++++++++++------ .../types/src/api/web/global/auditLogs.ts | 30 ++++---- 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/packages/backend-core/src/db/lucene.ts b/packages/backend-core/src/db/lucene.ts index 374e30a10d..e984fcdfdb 100644 --- a/packages/backend-core/src/db/lucene.ts +++ b/packages/backend-core/src/db/lucene.ts @@ -4,14 +4,25 @@ import { SearchFilters, Row } from "@budibase/types" const QUERY_START_REGEX = /\d[0-9]*:/g +interface SearchResponse { + rows: T[] | any[] + bookmark: string +} + +interface PaginatedSearchResponse extends SearchResponse { + hasNextPage: boolean +} + export type SearchParams = { - tableId: string + tableId?: string sort?: string sortOrder?: string sortType?: string limit?: number bookmark?: string version?: string + indexer?: () => Promise + disableEscaping?: boolean rows?: Row[] } @@ -30,7 +41,7 @@ export function removeKeyNumbering(key: any): string { * Class to build lucene query URLs. * Optionally takes a base lucene query object. */ -export class QueryBuilder { +export class QueryBuilder { dbName: string index: string query: SearchFilters @@ -70,10 +81,12 @@ export class QueryBuilder { disableEscaping() { this.noEscaping = true + return this } setIndexBuilder(builderFn: () => Promise) { this.indexBuilder = builderFn + return this } setVersion(version?: string) { @@ -407,11 +420,11 @@ export class QueryBuilder { const fullPath = `${url}/${this.dbName}/_design/database/_search/${this.index}` const body = this.buildSearchBody() try { - return await runQuery(fullPath, body, cookie) + return await runQuery(fullPath, body, cookie) } catch (err: any) { if (err.status === 404 && this.indexBuilder) { await this.indexBuilder() - return await runQuery(fullPath, body, cookie) + return await runQuery(fullPath, body, cookie) } else { throw err } @@ -426,7 +439,11 @@ export class QueryBuilder { * @param cookie The auth cookie for CouchDB * @returns {Promise<{rows: []}>} */ -const runQuery = async (url: string, body: any, cookie: string) => { +async function runQuery( + url: string, + body: any, + cookie: string +): Promise> { const response = await fetch(url, { body: JSON.stringify(body), method: "POST", @@ -470,7 +487,7 @@ const runQuery = async (url: string, body: any, cookie: string) => { * rows {array|null} Current results in the recursive search * @returns {Promise<*[]|*>} */ -async function recursiveSearch( +async function recursiveSearch( dbName: string, index: string, query: any, @@ -485,7 +502,7 @@ async function recursiveSearch( if (rows.length > params.limit - 200) { pageSize = params.limit - rows.length } - const page = await new QueryBuilder(dbName, index, query) + const page = await new QueryBuilder(dbName, index, query) .setVersion(params.version) .setTable(params.tableId) .setBookmark(bookmark) @@ -525,7 +542,7 @@ async function recursiveSearch( * bookmark {string} The bookmark to resume from * @returns {Promise<{hasNextPage: boolean, rows: *[]}>} */ -export async function paginatedSearch( +export async function paginatedSearch( dbName: string, index: string, query: SearchFilters, @@ -536,12 +553,25 @@ export async function paginatedSearch( limit = 50 } limit = Math.min(limit, 200) - const search = new QueryBuilder(dbName, index, query) - .setVersion(params.version) - .setTable(params.tableId) - .setSort(params.sort) - .setSortOrder(params.sortOrder) - .setSortType(params.sortType) + const search = new QueryBuilder(dbName, index, query) + if (params.version) { + search.setVersion(params.version) + } + if (params.tableId) { + search.setTable(params.tableId) + } + if (params.sort) { + search + .setSort(params.sort) + .setSortOrder(params.sortOrder) + .setSortType(params.sortType) + } + if (params.indexer) { + search.setIndexBuilder(params.indexer) + } + if (params.disableEscaping) { + search.disableEscaping() + } const searchResults = await search .setBookmark(params.bookmark) .setLimit(limit) @@ -549,11 +579,11 @@ export async function paginatedSearch( // Try fetching 1 row in the next page to see if another page of results // exists or not - const nextResults = await search - .setTable(params.tableId) - .setBookmark(searchResults.bookmark) - .setLimit(1) - .run() + search.setBookmark(searchResults.bookmark).setLimit(1) + if (params.tableId) { + search.setTable(params.tableId) + } + const nextResults = await search.run() return { ...searchResults, @@ -578,7 +608,7 @@ export async function paginatedSearch( * limit {number} The desired number of results * @returns {Promise<{rows: *}>} */ -export async function fullSearch( +export async function fullSearch( dbName: string, index: string, query: SearchFilters, @@ -589,6 +619,6 @@ export async function fullSearch( limit = 1000 } params.limit = Math.min(limit, 1000) - const rows = await recursiveSearch(dbName, index, query, params) + const rows = await recursiveSearch(dbName, index, query, params) return { rows } } diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 443cd79aa1..480dbbfe2b 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -16,21 +16,23 @@ export interface SearchAuditLogsRequest extends PaginationRequest, AuditLogSearchParams {} -export interface SearchAuditLogsResponse extends PaginationResponse { - data: { - app: { - _id: string - name: string - } - user: { - _id: string - name: string - } - event: Event - timestamp: string +export interface AuditLogEnriched { + app: { + _id: string name: string - metadata: any - }[] + } + user: { + _id: string + name: string + } + event: Event + timestamp: string + name: string + metadata: any +} + +export interface SearchAuditLogsResponse extends PaginationResponse { + data: AuditLogEnriched[] } export interface DefinitionsAuditLogsResponse { From 70e525b92850628047d858d4353728fd058e84e8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 17 Feb 2023 19:00:45 +0000 Subject: [PATCH 046/273] Updating types for audit logs to correctly handle the deletion of resources like users or apps. --- packages/backend-core/src/db/lucene.ts | 14 +++++++------- packages/backend-core/src/db/utils.ts | 10 ++++++++++ packages/types/src/api/web/global/auditLogs.ts | 15 +++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/backend-core/src/db/lucene.ts b/packages/backend-core/src/db/lucene.ts index e984fcdfdb..4a44aaa073 100644 --- a/packages/backend-core/src/db/lucene.ts +++ b/packages/backend-core/src/db/lucene.ts @@ -13,7 +13,7 @@ interface PaginatedSearchResponse extends SearchResponse { hasNextPage: boolean } -export type SearchParams = { +export type SearchParams = { tableId?: string sort?: string sortOrder?: string @@ -23,7 +23,7 @@ export type SearchParams = { version?: string indexer?: () => Promise disableEscaping?: boolean - rows?: Row[] + rows?: T | Row[] } export function removeKeyNumbering(key: any): string { @@ -502,7 +502,7 @@ async function recursiveSearch( if (rows.length > params.limit - 200) { pageSize = params.limit - rows.length } - const page = await new QueryBuilder(dbName, index, query) + const page = await new QueryBuilder(dbName, index, query) .setVersion(params.version) .setTable(params.tableId) .setBookmark(bookmark) @@ -546,14 +546,14 @@ export async function paginatedSearch( dbName: string, index: string, query: SearchFilters, - params: SearchParams + params: SearchParams ) { let limit = params.limit if (limit == null || isNaN(limit) || limit < 0) { limit = 50 } limit = Math.min(limit, 200) - const search = new QueryBuilder(dbName, index, query) + const search = new QueryBuilder(dbName, index, query) if (params.version) { search.setVersion(params.version) } @@ -612,13 +612,13 @@ export async function fullSearch( dbName: string, index: string, query: SearchFilters, - params: SearchParams + params: SearchParams ) { let limit = params.limit if (limit == null || isNaN(limit) || limit < 0) { limit = 1000 } params.limit = Math.min(limit, 1000) - const rows = await recursiveSearch(dbName, index, query, params) + const rows = await recursiveSearch(dbName, index, query, params) return { rows } } diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index 233d044eaa..c22685b912 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -366,6 +366,16 @@ export async function getAllApps({ } } +export async function getAppsById(appIds: string[]) { + const settled = await Promise.allSettled( + appIds.map(appId => getAppMetadata(appId)) + ) + // have to list the apps which exist, some may have been deleted + return settled + .filter(promise => promise.status === "fulfilled") + .map(promise => (promise as PromiseFulfilledResult).value) +} + /** * Utility function for getAllApps but filters to production apps only. */ diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 480dbbfe2b..5a0cf4f398 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -1,5 +1,6 @@ import { Event, AuditedEventFriendlyName } from "../../../sdk" import { PaginationResponse, PaginationRequest } from "../" +import { User, App } from "../../../" export interface AuditLogSearchParams { userId?: string[] @@ -16,15 +17,13 @@ export interface SearchAuditLogsRequest extends PaginationRequest, AuditLogSearchParams {} +export enum AuditLogResourceStatus { + DELETED = "deleted", +} + export interface AuditLogEnriched { - app: { - _id: string - name: string - } - user: { - _id: string - name: string - } + app?: App | { _id: string; status: AuditLogResourceStatus } + user: User | { _id: string; status: AuditLogResourceStatus } event: Event timestamp: string name: string From 246f5eb5e477f6d6aa716b50b0e8c6e1bb03a78e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 20 Feb 2023 10:15:29 +0000 Subject: [PATCH 047/273] bumping qa core types and backend core dependencies --- qa-core/package.json | 6 +- qa-core/yarn.lock | 353 ++++++++++++++++++++++++++++++++----------- 2 files changed, 265 insertions(+), 94 deletions(-) diff --git a/qa-core/package.json b/qa-core/package.json index 7733e95d46..15246af294 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -38,7 +38,7 @@ ] }, "devDependencies": { - "@budibase/types": "1.3.4", + "@budibase/types": "^2.3.17", "@types/jest": "29.0.0", "@types/node-fetch": "2.6.2", "chance": "1.1.8", @@ -53,8 +53,8 @@ "typescript": "4.7.3" }, "dependencies": { - "@budibase/backend-core": "^2.0.5", + "@budibase/backend-core": "^2.3.17", "form-data": "^4.0.0", "node-fetch": "2" } -} \ No newline at end of file +} diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock index b090ff872f..be6207bbad 100644 --- a/qa-core/yarn.lock +++ b/qa-core/yarn.lock @@ -297,27 +297,30 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.0.5.tgz#e720ad8a0fd0eb0157d8ec332e530b481fd5b912" - integrity sha512-uY/YQgZ1xTm3npzWNRgZQBY/nj2ZxSkGtGbgK4NyWwZzvVUwd9vfNAIdKf7crECMJncH1x4H9TalQoFXb/cmbA== +"@budibase/backend-core@^2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17.tgz#27c8c2144bfda1533b43da6de7111c0819aea6a5" + integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== dependencies: - "@budibase/types" "^2.0.5" + "@budibase/nano" "10.1.1" + "@budibase/types" "^2.3.17" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" + aws-cloudfront-sign "2.2.0" aws-sdk "2.1030.0" bcrypt "5.0.1" bcryptjs "2.4.3" + bull "4.10.1" + correlation-id "4.0.0" dotenv "16.0.1" emitter-listener "1.1.2" ioredis "4.28.0" joi "17.6.0" - jsonwebtoken "8.5.1" + jsonwebtoken "9.0.0" koa-passport "4.1.4" lodash "4.17.21" lodash.isarguments "3.1.0" node-fetch "2.6.7" - passport-google-auth "1.0.2" passport-google-oauth "2.0.0" passport-jwt "4.0.0" passport-local "1.0.0" @@ -333,15 +336,22 @@ uuid "8.3.2" zlib "1.0.5" -"@budibase/types@1.3.4": - version "1.3.4" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.4.tgz#25f087b024e843eb372e50c81f8f925fb39f1dfd" - integrity sha512-ndyWs8yeCS7cpZjApDB1HhY6UUM2SRBUgAMCZOZaWABG9JHeCbx7x0e/pA2SZjswdMXqS5WmnEd3br5wuvUzJw== +"@budibase/nano@10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" + integrity sha512-kbMIzMkjVtl+xI0UPwVU0/pn8/ccxTyfzwBz6Z+ZiN2oUSb0fJCe0qwA6o8dxwSa8nZu4MbGAeMJl3CJndmWtA== + dependencies: + "@types/tough-cookie" "^4.0.2" + axios "^1.1.3" + http-cookie-agent "^4.0.2" + node-abort-controller "^3.0.1" + qs "^6.11.0" + tough-cookie "^4.1.2" -"@budibase/types@^2.0.5": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.0.5.tgz#852c86611f237640b59d8dc4ae0c8c5fec491cf1" - integrity sha512-MnnDEB22kbXRsztmHPgvFDSYavpb0qm6H6Y/3UHXKqyFEg/KRpiF1p7lYsN+FAUDAWxpFgI+kp2Yw6gWyA5FLQ== +"@budibase/types@^2.3.17": + version "2.3.17" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17.tgz#d97c1de5fb03c91ff7e55d7c8c3901e5e2e95995" + integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -660,6 +670,36 @@ semver "^7.3.5" tar "^6.1.11" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.0.tgz#d31a238c943ffc34bab73ad6ce7a6466d65888ef" + integrity sha512-5qpnNHUyyEj9H3sm/4Um/bnx1lrQGhe8iqry/1d+cQYCRd/gzYA0YLeq0ezlk4hKx4vO+dsEsNyeowqRqslwQA== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.0.tgz#2f6fbbec3d3f0bbe9c6678c899f1c1a6e25ed980" + integrity sha512-ZphTFFd6SFweNAMKD+QJCrWpgkjf4qBuHltiMkKkD6FFrB3NOTRVmetAGTkJ57pa+s6J0yCH06LujWB9rZe94g== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.0.tgz#19875441da50b9aa8f8e726eb097a4cead435a3f" + integrity sha512-NEX6hdSvP4BmVyegaIbrGxvHzHvTzzsPaxXCsUt0mbLbPpEftsvNwaEVKOowXnLoeuGeD4MaqSwL3BUK2elsUA== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.0.tgz#3b855ac72cc16e89db2f72adf47ddc964c20a53d" + integrity sha512-ztKVV1dO/sSZyGse0PBCq3Pk1PkYjsA/dsEWE7lfrGoAK3i9HpS2o7XjGQ7V4va6nX+xPPOiuYpQwa4Bi6vlww== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.0.tgz#455f1d5bb00e87f78c67711f26e7bff9f1457684" + integrity sha512-9uvdAkZMOPCY7SPRxZLW8XGqBOVNVEhqlgffenN8shA1XR9FWVsSM13nr/oHtNgXg6iVyML7RwWPyqUeThlwxg== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.0.tgz#03c6bfcd3acb179ea69546c20d50895b9d623ada" + integrity sha512-Wg0+9615kHKlr9iLVcG5I+/CHnf6w3x5UADRv8Ad16yA0Bu5l9eVOROjV7aHPG6uC8ZPFIVVaoSjDChD+Y0pzg== + "@shopify/jest-koa-mocks@5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@shopify/jest-koa-mocks/-/jest-koa-mocks-5.0.1.tgz#fba490b6b7985fbb571eb9974897d396a3642e94" @@ -825,6 +865,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== +"@types/tough-cookie@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" + integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -889,7 +934,7 @@ acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -987,18 +1032,18 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -async@~2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" - integrity sha512-+g/Ncjbx0JSq2Mk03WQkyKvNh5q9Qvyo/RIqIqnmC5feJY70PNl2ESwZU2BhAB+AZPkHNzzyC2Dq2AS5VnTKhQ== - dependencies: - lodash "^4.14.0" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +aws-cloudfront-sign@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/aws-cloudfront-sign/-/aws-cloudfront-sign-2.2.0.tgz#3910f5a6d0d90fec07f2b4ef8ab07f3eefb5625d" + integrity sha512-qG+rwZMP3KRTPPbVmWY8DlrT56AkA4iVOeo23vkdK2EXeW/brJFN2haSNKzVz+oYhFMEIzVVloeAcrEzuRkuVQ== + dependencies: + lodash "^3.6.0" + aws-sdk@2.1030.0: version "2.1030.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1030.0.tgz#24a856af3d2b8b37c14a8f59974993661c66fd82" @@ -1046,6 +1091,15 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" +axios@^1.1.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.3.tgz#e7011384ba839b885007c9c9fae1ff23dceb295b" + integrity sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-jest@^28.1.3: version "28.1.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" @@ -1226,6 +1280,21 @@ buffer@^5.5.0, buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" +bull@4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/bull/-/bull-4.10.1.tgz#f14974b6089358b62b495a2cbf838aadc098e43f" + integrity sha512-Fp21tRPb2EaZPVfmM+ONZKVz2RA+to+zGgaTLyCKt3JMSU8OOBqK8143OQrnGuGpsyE5G+9FevFAGhdZZfQP2g== + dependencies: + cron-parser "^4.2.1" + debuglog "^1.0.0" + get-port "^5.1.1" + ioredis "^4.28.5" + lodash "^4.17.21" + msgpackr "^1.5.2" + p-timeout "^3.2.0" + semver "^7.3.2" + uuid "^8.3.0" + cache-content-type@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" @@ -1234,6 +1303,14 @@ cache-content-type@^1.0.0: mime-types "^2.1.18" ylru "^1.2.0" +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1438,11 +1515,25 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +correlation-id@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/correlation-id/-/correlation-id-4.0.0.tgz#c1d3038e5f30d7bfeae5728ff96f27a7506bc2c0" + integrity sha512-WvXtJBlovvOBKqTz/YwWP2gm6CXJZJArfGimp9s/ehmhJMPFbmnPMQe3K60Q9idGNixMvKojMjleyDhZEFdHfg== + dependencies: + uuid "^8.3.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== +cron-parser@^4.2.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-4.7.1.tgz#1e325a6a18e797a634ada1e2599ece0b6b5ed177" + integrity sha512-WguFaoQ0hQ61SgsCZLHUcNbAvlK0lypKXu62ARguefYmjzaOXIVRNrAmyXzabTwUn4sQvQLkk6bjH+ipGfw8bA== + dependencies: + luxon "^3.2.1" + cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1478,6 +1569,11 @@ debug@4.3.2: dependencies: ms "2.1.2" +debuglog@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw== + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -1820,7 +1916,7 @@ follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== -follow-redirects@^1.14.4: +follow-redirects@^1.14.4, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -1919,11 +2015,25 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-intrinsic@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -1953,47 +2063,11 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -google-auth-library@~0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" - integrity sha512-KM54Y9GhdAzfXUHmWEoYmaOykSLuMG7W4HvVLYqyogxOyE6px8oSS8W13ngqW0oDGZ915GFW3V6OM6+qcdvPOA== - dependencies: - gtoken "^1.2.1" - jws "^3.1.4" - lodash.noop "^3.0.1" - request "^2.74.0" - -google-p12-pem@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" - integrity sha512-puhMlJ2+E/rgvxWaqgN/nC7x623OAE8MR9vBUqxF0inCE7HoVfCHvTeQ9+BR+rj9KM0fIg6XV6tmbt7XHHssoQ== - dependencies: - node-forge "^0.7.1" - -googleapis@^16.0.0: - version "16.1.0" - resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" - integrity sha512-5czmF7xkIlJKc1+/+5tltrI1skoR3HKtkDOld9rk+DOucTpZRjOhCoJzoSjxB3M8rP2tEb1VIr1TPyzR3V2PUQ== - dependencies: - async "~2.1.4" - google-auth-library "~0.10.0" - string-template "~1.0.0" - graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -gtoken@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" - integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== - dependencies: - google-p12-pem "^0.1.0" - jws "^3.0.0" - mime "^1.4.1" - request "^2.72.0" - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -2017,7 +2091,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.2: +has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -2054,6 +2128,13 @@ http-assert@^1.3.0: deep-equal "~1.0.1" http-errors "~1.8.0" +http-cookie-agent@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/http-cookie-agent/-/http-cookie-agent-4.0.2.tgz#dcdaae18ed1f7452d81ae4d5cd80b227d6831b69" + integrity sha512-noTmxdH5CuytTnLj/Qv3Z84e/YFq8yLXAw3pqIYZ25Edhb9pQErIAC+ednw40Cic6Le/h9ryph5/TqsvkOaUCw== + dependencies: + agent-base "^6.0.2" + http-errors@^1.6.3, http-errors@~1.8.0: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" @@ -2150,6 +2231,23 @@ ioredis@4.28.0: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ioredis@^4.28.5: + version "4.28.5" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.5.tgz#5c149e6a8d76a7f8fa8a504ffc85b7d5b6797f9f" + integrity sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -2745,7 +2843,17 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== -jsonwebtoken@8.5.1, jsonwebtoken@^8.2.0: +jsonwebtoken@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" + integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw== + dependencies: + jws "^3.2.2" + lodash "^4.17.21" + ms "^2.1.1" + semver "^7.3.8" + +jsonwebtoken@^8.2.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -2780,7 +2888,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: +jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -3017,11 +3125,6 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash.noop@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" - integrity sha512-TmYdmu/pebrdTIBDK/FDx9Bmfzs9x0sZG6QIJuMDTqEPfeciLcN13ij+cOd0i9vwJfBtbG9UQ+C7MkXgYxrIJg== - lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -3032,11 +3135,16 @@ lodash.pick@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== -lodash@4.17.21, lodash@^4.14.0, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lodash@^3.6.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + integrity sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3049,6 +3157,11 @@ ltgt@2.2.1, ltgt@^2.1.2: resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== +luxon@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.2.1.tgz#14f1af209188ad61212578ea7e3d518d18cee45f" + integrity sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg== + make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -3122,7 +3235,7 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24, dependencies: mime-db "1.52.0" -mime@^1.3.4, mime@^1.4.1: +mime@^1.3.4: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -3179,6 +3292,27 @@ ms@^2.1.1, ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.0.tgz#5b5c5fbfff25be5ee5b5a82a9cbe02e37f72bed0" + integrity sha512-oy6KCk1+X4Bn5m6Ycq5N1EWl9npqG/cLrE8ga8NX7ZqfqYUUBS08beCQaGq80fjbKBySur0E6x//yZjzNJDt3A== + dependencies: + node-gyp-build-optional-packages "5.0.7" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.0" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.0" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.0" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.0" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.0" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.0" + +msgpackr@^1.5.2: + version "1.8.3" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.3.tgz#78c1b91359f72707f4abeaca40cc423bd2d75185" + integrity sha512-m2JefwcKNzoHYXkH/5jzHRxAw7XLWsAdvu0FOJ+OLwwozwOV/J6UA62iLkfIMbg7G8+dIuRwgg6oz+QoQ4YkoA== + optionalDependencies: + msgpackr-extract "^3.0.0" + napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" @@ -3204,6 +3338,11 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +node-abort-controller@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" + integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== + node-addon-api@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -3221,10 +3360,10 @@ node-fetch@2.6.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== -node-forge@^0.7.1: - version "0.7.6" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" - integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== +node-gyp-build-optional-packages@5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" + integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== node-gyp-build@~4.1.0: version "4.1.1" @@ -3301,6 +3440,11 @@ object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + on-finished@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -3327,6 +3471,11 @@ only@~0.0.2: resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ== +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -3353,6 +3502,13 @@ p-map@^2.1.0: resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -3373,14 +3529,6 @@ parseurl@^1.3.2, parseurl@^1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -passport-google-auth@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" - integrity sha512-cfAqna6jZLyMEwUdd4PIwAh2mQKQVEDAaRIaom1pG6h4x4Gwjllf/Jflt3TkR1Sen5Rkvr3l7kSXCWE1EKkh8g== - dependencies: - googleapis "^16.0.0" - passport-strategy "1.x" - passport-google-oauth1@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" @@ -3443,7 +3591,7 @@ passport-oauth2@1.x.x: uid2 "0.0.x" utils-merge "1.x.x" -passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: +passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA== @@ -3720,6 +3868,11 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -3755,6 +3908,13 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +qs@^6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" @@ -3851,7 +4011,7 @@ remove-trailing-slash@^0.1.1: resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== -request@^2.72.0, request@^2.74.0, request@^2.88.0: +request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -3974,6 +4134,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.2, semver@^7.3.8: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -4001,6 +4168,15 @@ shimmer@^1.2.0: resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -4123,11 +4299,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-template@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" - integrity sha512-SLqR3GBUXuoPP5MmYtD7ompvXiG87QjT6lzOszyXjTM86Uu7At7vNnt2xgyTLq5o9T4IxTYFyGxcULqpsmsfdg== - "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -4315,7 +4486,7 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== @@ -4486,7 +4657,7 @@ uuid@8.1.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d" integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg== -uuid@8.3.2, uuid@^8.3.2: +uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.1, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== From 53f6b2b6e62443acfb6f79a17edcce6c18006842 Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Mon, 20 Feb 2023 11:03:37 +0000 Subject: [PATCH 048/273] Null safety (#9746) --- .../design/settings/controls/FilterEditor/FilterDrawer.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte index bf07cddf23..f56d7a78d4 100644 --- a/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/FilterEditor/FilterDrawer.svelte @@ -254,8 +254,8 @@ {:else if filter.type === "datetime"} {:else} From b60013cbb86f9b4c9207fddc123dfcb250d3b11a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Feb 2023 11:29:43 +0000 Subject: [PATCH 049/273] switching metadataSearch to fullSearch. --- .../server/src/api/controllers/row/internalSearch.ts | 9 ++++++--- packages/types/src/api/web/global/auditLogs.ts | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/controllers/row/internalSearch.ts b/packages/server/src/api/controllers/row/internalSearch.ts index f2abc91b14..bdb9379334 100644 --- a/packages/server/src/api/controllers/row/internalSearch.ts +++ b/packages/server/src/api/controllers/row/internalSearch.ts @@ -1,9 +1,9 @@ import { db as dbCore, context, SearchParams } from "@budibase/backend-core" -import { SearchFilters } from "@budibase/types" +import { SearchFilters, Row } from "@budibase/types" export async function paginatedSearch( query: SearchFilters, - params: SearchParams + params: SearchParams ) { const appId = context.getAppId() return dbCore.paginatedSearch( @@ -14,7 +14,10 @@ export async function paginatedSearch( ) } -export async function fullSearch(query: SearchFilters, params: SearchParams) { +export async function fullSearch( + query: SearchFilters, + params: SearchParams +) { const appId = context.getAppId() return dbCore.fullSearch(appId!, dbCore.SearchIndexes.ROWS, query, params) } diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 5a0cf4f398..dbd22b2bf2 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -8,7 +8,7 @@ export interface AuditLogSearchParams { event?: Event[] startDate?: string endDate?: string - metadataSearch?: string + fullSearch?: string } export interface DownloadAuditLogsRequest extends AuditLogSearchParams {} From 1eb2307fed412287ee53c9552fb543a5caed0d68 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Feb 2023 15:35:14 +0000 Subject: [PATCH 050/273] Fix for #9749 - static formulas would sometimes attempt to update the same row multiple times, filter down to just the unique row list which requires updating. --- packages/server/src/api/controllers/row/staticFormula.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/staticFormula.ts b/packages/server/src/api/controllers/row/staticFormula.ts index 47a5af8f5a..6ba44dc23a 100644 --- a/packages/server/src/api/controllers/row/staticFormula.ts +++ b/packages/server/src/api/controllers/row/staticFormula.ts @@ -38,7 +38,13 @@ export async function updateRelatedFormula( if (!relatedRows[relatedTableId]) { relatedRows[relatedTableId] = [] } - relatedRows[relatedTableId] = relatedRows[relatedTableId].concat(field) + // filter down to the rows which are not already included in related + const currentIds = relatedRows[relatedTableId].map(row => row._id) + const uniqueRelatedRows = field.filter( + (row: Row) => !currentIds.includes(row._id) + ) + relatedRows[relatedTableId] = + relatedRows[relatedTableId].concat(uniqueRelatedRows) } } for (let tableId of table.relatedFormula) { From 6cc96f39b17ff3ac6a2fbd2185d7664c8e95a0ab Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 20 Feb 2023 17:20:42 +0000 Subject: [PATCH 051/273] Minor fixes for friendly audited events, and a new function for comparing app IDs. --- packages/backend-core/src/db/utils.ts | 10 ++++++++++ packages/types/src/api/web/global/auditLogs.ts | 2 +- packages/types/src/sdk/events/event.ts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/backend-core/src/db/utils.ts b/packages/backend-core/src/db/utils.ts index c22685b912..d9dbb809d1 100644 --- a/packages/backend-core/src/db/utils.ts +++ b/packages/backend-core/src/db/utils.ts @@ -392,6 +392,16 @@ export async function getDevAppIDs() { return apps.filter((id: any) => isDevAppID(id)) } +export function isSameAppID( + appId1: string | undefined, + appId2: string | undefined +) { + if (appId1 == undefined || appId2 == undefined) { + return false + } + return getProdAppID(appId1) === getProdAppID(appId2) +} + export async function dbExists(dbName: any) { return doWithDB( dbName, diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index dbd22b2bf2..ef9927b89a 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -35,5 +35,5 @@ export interface SearchAuditLogsResponse extends PaginationResponse { } export interface DefinitionsAuditLogsResponse { - events: typeof AuditedEventFriendlyName + events: Record } diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 4fb3e873ae..1be0ea2bdf 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -197,7 +197,7 @@ export const AuditedEventFriendlyName: Record = { [Event.USER_PERMISSION_ADMIN_REMOVED]: `User "{{ email }}" admin role removed`, [Event.USER_PERMISSION_BUILDER_ASSIGNED]: `User "{{ email }}" builder role assigned`, [Event.USER_PERMISSION_BUILDER_REMOVED]: `User "{{ email }}" builder role removed`, - [Event.USER_INVITED]: `User "{{ email }} invited`, + [Event.USER_INVITED]: `User "{{ email }}" invited`, [Event.USER_INVITED_ACCEPTED]: `User "{{ email }}" accepted invite`, [Event.USER_PASSWORD_UPDATED]: `User "{{ email }}" password updated`, [Event.USER_PASSWORD_RESET_REQUESTED]: `User "{{ email }}" password reset requested`, From cacf275a997fa1274a05a98b3bc86637ec69a8dd Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 21 Feb 2023 08:23:53 +0000 Subject: [PATCH 052/273] Prevent SSO users from setting / resetting a password (#9672) * Prevent SSO users from setting / resetting a password * Add support for ENABLE_SSO_MAINTENANCE_MODE * Add typing to self api and build out user update sdk * Integrate sso checks with user sdk. Integrate user sdk with self api * Test fixes * Move self update into SDK * Lock down maintenance mode to admin user * Fix typo * Add health status response and return type signature to accounts.getStatus * Remove some unnecessary comments * Make sso save user function non optional * Remove redundant check on sso auth details provider * Update syncProfilePicture function name to getProfilePictureUrl * Update packages/worker/src/sdk/users/events.ts Co-authored-by: Adria Navarro * Add ENABLE_EMAIL_TEST_MODE flag * Fix for logging in as sso user when existing user has password already * Hide password update and force reset from ui for sso users * Always disable sso maintenance mode in cloud --------- Co-authored-by: Adria Navarro --- .../src/{cloud => accounts}/accounts.ts | 23 +- .../src/{cloud => accounts}/api.ts | 0 packages/backend-core/src/accounts/index.ts | 1 + packages/backend-core/src/auth/auth.ts | 50 +++- .../backend-core/src/auth/tests/auth.spec.ts | 13 + .../backend-core/src/events/identification.ts | 6 +- .../middleware/passport/datasource/google.ts | 11 +- .../src/middleware/passport/local.ts | 56 +--- .../middleware/passport/{ => sso}/google.ts | 28 +- .../src/middleware/passport/{ => sso}/oidc.ts | 40 ++- .../src/middleware/passport/sso/sso.ts | 165 +++++++++++ .../passport/sso/tests/google.spec.ts | 67 +++++ .../passport/sso/tests/oidc.spec.ts | 152 ++++++++++ .../middleware/passport/sso/tests/sso.spec.ts | 196 +++++++++++++ .../middleware/passport/tests/google.spec.js | 79 ----- .../middleware/passport/tests/oidc.spec.js | 144 ---------- .../tests/third-party-common.seq.spec.js | 178 ------------ .../passport/tests/utilities/mock-data.js | 54 ---- .../middleware/passport/third-party-common.ts | 177 ------------ packages/backend-core/src/users.ts | 6 + packages/backend-core/src/utils/utils.ts | 45 +-- .../tests/utilities/mocks/accounts.ts | 13 - .../tests/utilities/mocks/index.ts | 5 +- .../tests/utilities/structures/accounts.ts | 36 ++- .../tests/utilities/structures/index.ts | 4 +- .../tests/utilities/structures/sso.ts | 100 +++++++ .../tests/utilities/structures/users.ts | 70 +++++ .../portal/_components/UserDropdown.svelte | 8 +- .../portal/users/users/[userId].svelte | 9 +- packages/builder/src/stores/portal/auth.js | 1 + packages/server/specs/openapi.json | 12 +- packages/server/specs/openapi.yaml | 6 +- .../src/integrations/tests/couchdb.spec.ts | 2 - packages/types/src/api/account/index.ts | 1 + packages/types/src/api/account/status.ts | 7 + packages/types/src/api/web/auth.ts | 25 ++ packages/types/src/api/web/index.ts | 1 + packages/types/src/api/web/user.ts | 21 +- .../types/src/documents/account/account.ts | 18 +- packages/types/src/documents/global/config.ts | 27 +- packages/types/src/documents/global/user.ts | 63 ++-- packages/types/src/sdk/index.ts | 2 + packages/types/src/sdk/sso.ts | 37 +++ packages/types/src/sdk/user.ts | 12 + packages/worker/scripts/dev/manage.js | 1 + .../worker/src/api/controllers/global/auth.ts | 147 +++++----- .../worker/src/api/controllers/global/self.ts | 70 ++--- .../src/api/controllers/global/users.ts | 43 ++- .../src/api/controllers/system/accounts.ts | 12 +- packages/worker/src/api/routes/global/auth.ts | 17 +- .../src/api/routes/global/tests/auth.spec.ts | 271 +++++++++++++++--- .../src/api/routes/global/tests/self.spec.ts | 7 +- .../api/routes/system/tests/accounts.spec.ts | 8 +- packages/worker/src/environment.ts | 16 +- packages/worker/src/index.ts | 6 + packages/worker/src/sdk/accounts/index.ts | 3 +- .../sdk/accounts/{accounts.ts => metadata.ts} | 1 - packages/worker/src/sdk/auth/auth.ts | 86 ++++++ packages/worker/src/sdk/auth/index.ts | 1 + packages/worker/src/sdk/users/events.ts | 4 + packages/worker/src/sdk/users/index.ts | 1 + .../worker/src/sdk/users/tests/users.spec.ts | 52 ++++ packages/worker/src/sdk/users/users.ts | 97 ++++--- .../worker/src/tests/TestConfiguration.ts | 4 +- packages/worker/src/tests/api/auth.ts | 60 ++-- packages/worker/src/tests/structures/index.ts | 2 - packages/worker/src/tests/structures/users.ts | 37 --- packages/worker/src/utilities/email.ts | 6 +- 68 files changed, 1803 insertions(+), 1120 deletions(-) rename packages/backend-core/src/{cloud => accounts}/accounts.ts (69%) rename packages/backend-core/src/{cloud => accounts}/api.ts (100%) create mode 100644 packages/backend-core/src/accounts/index.ts create mode 100644 packages/backend-core/src/auth/tests/auth.spec.ts rename packages/backend-core/src/middleware/passport/{ => sso}/google.ts (76%) rename packages/backend-core/src/middleware/passport/{ => sso}/oidc.ts (85%) create mode 100644 packages/backend-core/src/middleware/passport/sso/sso.ts create mode 100644 packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts create mode 100644 packages/backend-core/src/middleware/passport/sso/tests/oidc.spec.ts create mode 100644 packages/backend-core/src/middleware/passport/sso/tests/sso.spec.ts delete mode 100644 packages/backend-core/src/middleware/passport/tests/google.spec.js delete mode 100644 packages/backend-core/src/middleware/passport/tests/oidc.spec.js delete mode 100644 packages/backend-core/src/middleware/passport/tests/third-party-common.seq.spec.js delete mode 100644 packages/backend-core/src/middleware/passport/tests/utilities/mock-data.js delete mode 100644 packages/backend-core/src/middleware/passport/third-party-common.ts delete mode 100644 packages/backend-core/tests/utilities/mocks/accounts.ts create mode 100644 packages/backend-core/tests/utilities/structures/sso.ts create mode 100644 packages/backend-core/tests/utilities/structures/users.ts create mode 100644 packages/types/src/api/account/status.ts create mode 100644 packages/types/src/api/web/auth.ts create mode 100644 packages/types/src/sdk/sso.ts create mode 100644 packages/types/src/sdk/user.ts rename packages/worker/src/sdk/accounts/{accounts.ts => metadata.ts} (99%) create mode 100644 packages/worker/src/sdk/auth/auth.ts create mode 100644 packages/worker/src/sdk/auth/index.ts create mode 100644 packages/worker/src/sdk/users/tests/users.spec.ts delete mode 100644 packages/worker/src/tests/structures/users.ts diff --git a/packages/backend-core/src/cloud/accounts.ts b/packages/backend-core/src/accounts/accounts.ts similarity index 69% rename from packages/backend-core/src/cloud/accounts.ts rename to packages/backend-core/src/accounts/accounts.ts index 90fa7ab824..a16d0f1074 100644 --- a/packages/backend-core/src/cloud/accounts.ts +++ b/packages/backend-core/src/accounts/accounts.ts @@ -1,13 +1,24 @@ import API from "./api" import env from "../environment" import { Header } from "../constants" -import { CloudAccount } from "@budibase/types" +import { CloudAccount, HealthStatusResponse } from "@budibase/types" const api = new API(env.ACCOUNT_PORTAL_URL) +/** + * This client is intended to be used in a cloud hosted deploy only. + * Rather than relying on each consumer to perform the necessary environmental checks + * we use the following check to exit early with a undefined response which should be + * handled by the caller. + */ +const EXIT_EARLY = env.SELF_HOSTED || env.DISABLE_ACCOUNT_PORTAL + export const getAccount = async ( email: string ): Promise => { + if (EXIT_EARLY) { + return + } const payload = { email, } @@ -29,6 +40,9 @@ export const getAccount = async ( export const getAccountByTenantId = async ( tenantId: string ): Promise => { + if (EXIT_EARLY) { + return + } const payload = { tenantId, } @@ -47,7 +61,12 @@ export const getAccountByTenantId = async ( return json[0] } -export const getStatus = async () => { +export const getStatus = async (): Promise< + HealthStatusResponse | undefined +> => { + if (EXIT_EARLY) { + return + } const response = await api.get(`/api/status`, { headers: { [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY, diff --git a/packages/backend-core/src/cloud/api.ts b/packages/backend-core/src/accounts/api.ts similarity index 100% rename from packages/backend-core/src/cloud/api.ts rename to packages/backend-core/src/accounts/api.ts diff --git a/packages/backend-core/src/accounts/index.ts b/packages/backend-core/src/accounts/index.ts new file mode 100644 index 0000000000..f2ae03040e --- /dev/null +++ b/packages/backend-core/src/accounts/index.ts @@ -0,0 +1 @@ +export * from "./accounts" diff --git a/packages/backend-core/src/auth/auth.ts b/packages/backend-core/src/auth/auth.ts index bbefb2933d..bee245a3ae 100644 --- a/packages/backend-core/src/auth/auth.ts +++ b/packages/backend-core/src/auth/auth.ts @@ -1,10 +1,11 @@ const _passport = require("koa-passport") const LocalStrategy = require("passport-local").Strategy const JwtStrategy = require("passport-jwt").Strategy -import { getGlobalDB } from "../tenancy" +import { getGlobalDB } from "../context" const refresh = require("passport-oauth2-refresh") -import { Config } from "../constants" +import { Config, Cookie } from "../constants" import { getScopedConfig } from "../db" +import { getSessionsForUser, invalidateSessions } from "../security/sessions" import { jwt as jwtPassport, local, @@ -15,8 +16,11 @@ import { google, } from "../middleware" import { invalidateUser } from "../cache/user" -import { User } from "@budibase/types" +import { PlatformLogoutOpts, User } from "@budibase/types" import { logAlert } from "../logging" +import * as events from "../events" +import * as userCache from "../cache/user" +import { clearCookie, getCookie } from "../utils" export { auditLog, authError, @@ -29,6 +33,7 @@ export { google, oidc, } from "../middleware" +import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso" export const buildAuthMiddleware = authenticated export const buildTenancyMiddleware = tenancy export const buildCsrfMiddleware = csrf @@ -71,7 +76,7 @@ async function refreshOIDCAccessToken( if (!enrichedConfig) { throw new Error("OIDC Config contents invalid") } - strategy = await oidc.strategyFactory(enrichedConfig) + strategy = await oidc.strategyFactory(enrichedConfig, ssoSaveUserNoOp) } catch (err) { console.error(err) throw new Error("Could not refresh OAuth Token") @@ -103,7 +108,11 @@ async function refreshGoogleAccessToken( let strategy try { - strategy = await google.strategyFactory(config, callbackUrl) + strategy = await google.strategyFactory( + config, + callbackUrl, + ssoSaveUserNoOp + ) } catch (err: any) { console.error(err) throw new Error( @@ -161,6 +170,8 @@ export async function refreshOAuthToken( return refreshResponse } +// TODO: Refactor to use user save function instead to prevent the need for +// manually saving and invalidating on callback export async function updateUserOAuth(userId: string, oAuthConfig: any) { const details = { accessToken: oAuthConfig.accessToken, @@ -188,3 +199,32 @@ export async function updateUserOAuth(userId: string, oAuthConfig: any) { console.error("Could not update OAuth details for current user", e) } } + +/** + * Logs a user out from budibase. Re-used across account portal and builder. + */ +export async function platformLogout(opts: PlatformLogoutOpts) { + const ctx = opts.ctx + const userId = opts.userId + const keepActiveSession = opts.keepActiveSession + + if (!ctx) throw new Error("Koa context must be supplied to logout.") + + const currentSession = getCookie(ctx, Cookie.Auth) + let sessions = await getSessionsForUser(userId) + + if (keepActiveSession) { + sessions = sessions.filter( + session => session.sessionId !== currentSession.sessionId + ) + } else { + // clear cookies + clearCookie(ctx, Cookie.Auth) + clearCookie(ctx, Cookie.CurrentApp) + } + + const sessionIds = sessions.map(({ sessionId }) => sessionId) + await invalidateSessions(userId, { sessionIds, reason: "logout" }) + await events.auth.logout() + await userCache.invalidateUser(userId) +} diff --git a/packages/backend-core/src/auth/tests/auth.spec.ts b/packages/backend-core/src/auth/tests/auth.spec.ts new file mode 100644 index 0000000000..307f6a63c8 --- /dev/null +++ b/packages/backend-core/src/auth/tests/auth.spec.ts @@ -0,0 +1,13 @@ +import { structures, testEnv } from "../../../tests" +import * as auth from "../auth" +import * as events from "../../events" + +describe("platformLogout", () => { + it("should call platform logout", async () => { + await testEnv.withTenant(async () => { + const ctx = structures.koa.newContext() + await auth.platformLogout({ ctx, userId: "test" }) + expect(events.auth.logout).toBeCalledTimes(1) + }) + }) +}) diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts index 8ac22b471c..7cade9e14b 100644 --- a/packages/backend-core/src/events/identification.ts +++ b/packages/backend-core/src/events/identification.ts @@ -16,6 +16,7 @@ import { InstallationGroup, UserContext, Group, + isSSOUser, } from "@budibase/types" import { processors } from "./processors" import * as dbUtils from "../db/utils" @@ -166,7 +167,10 @@ const identifyUser = async ( const type = IdentityType.USER let builder = user.builder?.global || false let admin = user.admin?.global || false - let providerType = user.providerType + let providerType + if (isSSOUser(user)) { + providerType = user.providerType + } const accountHolder = account?.budibaseUserId === user._id || false const verified = account && account?.budibaseUserId === user._id ? account.verified : false diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts index 65620d7aa3..112f8d2096 100644 --- a/packages/backend-core/src/middleware/passport/datasource/google.ts +++ b/packages/backend-core/src/middleware/passport/datasource/google.ts @@ -1,10 +1,11 @@ -import * as google from "../google" +import * as google from "../sso/google" import { Cookie, Config } from "../../../constants" import { clearCookie, getCookie } from "../../../utils" import { getScopedConfig, getPlatformUrl, doWithDB } from "../../../db" import environment from "../../../environment" -import { getGlobalDB } from "../../../tenancy" +import { getGlobalDB } from "../../../context" import { BBContext, Database, SSOProfile } from "@budibase/types" +import { ssoSaveUserNoOp } from "../sso/sso" const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy type Passport = { @@ -36,7 +37,11 @@ export async function preAuth( const platformUrl = await getPlatformUrl({ tenantAware: false }) let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback` - const strategy = await google.strategyFactory(googleConfig, callbackUrl) + const strategy = await google.strategyFactory( + googleConfig, + callbackUrl, + ssoSaveUserNoOp + ) if (!ctx.query.appId || !ctx.query.datasourceId) { ctx.throw(400, "appId and datasourceId query params not present.") diff --git a/packages/backend-core/src/middleware/passport/local.ts b/packages/backend-core/src/middleware/passport/local.ts index 8b85d3734c..e198032532 100644 --- a/packages/backend-core/src/middleware/passport/local.ts +++ b/packages/backend-core/src/middleware/passport/local.ts @@ -1,15 +1,10 @@ import { UserStatus } from "../../constants" -import { compare, newid } from "../../utils" -import env from "../../environment" +import { compare } from "../../utils" import * as users from "../../users" import { authError } from "./utils" -import { createASession } from "../../security/sessions" -import { getTenantId } from "../../tenancy" import { BBContext } from "@budibase/types" -const jwt = require("jsonwebtoken") const INVALID_ERR = "Invalid credentials" -const SSO_NO_PASSWORD = "SSO user does not have a password set" const EXPIRED = "This account has expired. Please reset your password" export const options = { @@ -35,50 +30,25 @@ export async function authenticate( const dbUser = await users.getGlobalUserByEmail(email) if (dbUser == null) { - return authError(done, `User not found: [${email}]`) - } - - // check that the user is currently inactive, if this is the case throw invalid - if (dbUser.status === UserStatus.INACTIVE) { + console.info(`user=${email} could not be found`) return authError(done, INVALID_ERR) } - // check that the user has a stored password before proceeding - if (!dbUser.password) { - if ( - (dbUser.account && dbUser.account.authType === "sso") || // root account sso - dbUser.thirdPartyProfile // internal sso - ) { - return authError(done, SSO_NO_PASSWORD) - } + if (dbUser.status === UserStatus.INACTIVE) { + console.info(`user=${email} is inactive`, dbUser) + return authError(done, INVALID_ERR) + } - console.error("Non SSO usser has no password set", dbUser) + if (!dbUser.password) { + console.info(`user=${email} has no password set`, dbUser) return authError(done, EXPIRED) } - // authenticate - if (await compare(password, dbUser.password)) { - const sessionId = newid() - const tenantId = getTenantId() - - await createASession(dbUser._id!, { sessionId, tenantId }) - - const token = jwt.sign( - { - userId: dbUser._id, - sessionId, - tenantId, - }, - env.JWT_SECRET - ) - // Remove users password in payload - delete dbUser.password - - return done(null, { - ...dbUser, - token, - }) - } else { + if (!(await compare(password, dbUser.password))) { return authError(done, INVALID_ERR) } + + // intentionally remove the users password in payload + delete dbUser.password + return done(null, dbUser) } diff --git a/packages/backend-core/src/middleware/passport/google.ts b/packages/backend-core/src/middleware/passport/sso/google.ts similarity index 76% rename from packages/backend-core/src/middleware/passport/google.ts rename to packages/backend-core/src/middleware/passport/sso/google.ts index dd3dc8b86d..d26d7d6a8d 100644 --- a/packages/backend-core/src/middleware/passport/google.ts +++ b/packages/backend-core/src/middleware/passport/sso/google.ts @@ -1,18 +1,26 @@ -import { ssoCallbackUrl } from "./utils" -import { authenticateThirdParty, SaveUserFunction } from "./third-party-common" -import { ConfigType, GoogleConfig, Database, SSOProfile } from "@budibase/types" +import { ssoCallbackUrl } from "../utils" +import * as sso from "./sso" +import { + ConfigType, + GoogleConfig, + Database, + SSOProfile, + SSOAuthDetails, + SSOProviderType, + SaveSSOUserFunction, +} from "@budibase/types" const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy -export function buildVerifyFn(saveUserFn?: SaveUserFunction) { +export function buildVerifyFn(saveUserFn: SaveSSOUserFunction) { return ( accessToken: string, refreshToken: string, profile: SSOProfile, done: Function ) => { - const thirdPartyUser = { - provider: profile.provider, // should always be 'google' - providerType: "google", + const details: SSOAuthDetails = { + provider: "google", + providerType: SSOProviderType.GOOGLE, userId: profile.id, profile: profile, email: profile._json.email, @@ -22,8 +30,8 @@ export function buildVerifyFn(saveUserFn?: SaveUserFunction) { }, } - return authenticateThirdParty( - thirdPartyUser, + return sso.authenticate( + details, true, // require local accounts to exist done, saveUserFn @@ -39,7 +47,7 @@ export function buildVerifyFn(saveUserFn?: SaveUserFunction) { export async function strategyFactory( config: GoogleConfig["config"], callbackUrl: string, - saveUserFn?: SaveUserFunction + saveUserFn: SaveSSOUserFunction ) { try { const { clientID, clientSecret } = config diff --git a/packages/backend-core/src/middleware/passport/oidc.ts b/packages/backend-core/src/middleware/passport/sso/oidc.ts similarity index 85% rename from packages/backend-core/src/middleware/passport/oidc.ts rename to packages/backend-core/src/middleware/passport/sso/oidc.ts index 7caa177cf0..1fb44b84a3 100644 --- a/packages/backend-core/src/middleware/passport/oidc.ts +++ b/packages/backend-core/src/middleware/passport/sso/oidc.ts @@ -1,22 +1,20 @@ import fetch from "node-fetch" -import { authenticateThirdParty, SaveUserFunction } from "./third-party-common" -import { ssoCallbackUrl } from "./utils" +import * as sso from "./sso" +import { ssoCallbackUrl } from "../utils" import { ConfigType, - OIDCInnerCfg, + OIDCInnerConfig, Database, SSOProfile, - ThirdPartyUser, - OIDCConfiguration, + OIDCStrategyConfiguration, + SSOAuthDetails, + SSOProviderType, + JwtClaims, + SaveSSOUserFunction, } from "@budibase/types" const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy -type JwtClaims = { - preferred_username: string - email: string -} - -export function buildVerifyFn(saveUserFn?: SaveUserFunction) { +export function buildVerifyFn(saveUserFn: SaveSSOUserFunction) { /** * @param {*} issuer The identity provider base URL * @param {*} sub The user ID @@ -39,10 +37,10 @@ export function buildVerifyFn(saveUserFn?: SaveUserFunction) { params: any, done: Function ) => { - const thirdPartyUser: ThirdPartyUser = { + const details: SSOAuthDetails = { // store the issuer info to enable sync in future provider: issuer, - providerType: "oidc", + providerType: SSOProviderType.OIDC, userId: profile.id, profile: profile, email: getEmail(profile, jwtClaims), @@ -52,8 +50,8 @@ export function buildVerifyFn(saveUserFn?: SaveUserFunction) { }, } - return authenticateThirdParty( - thirdPartyUser, + return sso.authenticate( + details, false, // don't require local accounts to exist done, saveUserFn @@ -104,8 +102,8 @@ function validEmail(value: string) { * @returns Dynamically configured Passport OIDC Strategy */ export async function strategyFactory( - config: OIDCConfiguration, - saveUserFn?: SaveUserFunction + config: OIDCStrategyConfiguration, + saveUserFn: SaveSSOUserFunction ) { try { const verify = buildVerifyFn(saveUserFn) @@ -119,14 +117,14 @@ export async function strategyFactory( } export async function fetchStrategyConfig( - enrichedConfig: OIDCInnerCfg, + oidcConfig: OIDCInnerConfig, callbackUrl?: string -): Promise { +): Promise { try { - const { clientID, clientSecret, configUrl } = enrichedConfig + const { clientID, clientSecret, configUrl } = oidcConfig if (!clientID || !clientSecret || !callbackUrl || !configUrl) { - //check for remote config and all required elements + // check for remote config and all required elements throw new Error( "Configuration invalid. Must contain clientID, clientSecret, callbackUrl and configUrl" ) diff --git a/packages/backend-core/src/middleware/passport/sso/sso.ts b/packages/backend-core/src/middleware/passport/sso/sso.ts new file mode 100644 index 0000000000..2fc1184722 --- /dev/null +++ b/packages/backend-core/src/middleware/passport/sso/sso.ts @@ -0,0 +1,165 @@ +import { generateGlobalUserID } from "../../../db" +import { authError } from "../utils" +import * as users from "../../../users" +import * as context from "../../../context" +import fetch from "node-fetch" +import { + SaveSSOUserFunction, + SaveUserOpts, + SSOAuthDetails, + SSOUser, + User, +} from "@budibase/types" + +// no-op function for user save +// - this allows datasource auth and access token refresh to work correctly +// - prefer no-op over an optional argument to ensure function is provided to login flows +export const ssoSaveUserNoOp: SaveSSOUserFunction = ( + user: SSOUser, + opts: SaveUserOpts +) => Promise.resolve(user) + +/** + * Common authentication logic for third parties. e.g. OAuth, OIDC. + */ +export async function authenticate( + details: SSOAuthDetails, + requireLocalAccount: boolean = true, + done: any, + saveUserFn: SaveSSOUserFunction +) { + if (!saveUserFn) { + throw new Error("Save user function must be provided") + } + if (!details.userId) { + return authError(done, "sso user id required") + } + if (!details.email) { + return authError(done, "sso user email required") + } + + // use the third party id + const userId = generateGlobalUserID(details.userId) + + let dbUser: User | undefined + + // try to load by id + try { + dbUser = await users.getById(userId) + } catch (err: any) { + // abort when not 404 error + if (!err.status || err.status !== 404) { + return authError( + done, + "Unexpected error when retrieving existing user", + err + ) + } + } + + // fallback to loading by email + if (!dbUser) { + dbUser = await users.getGlobalUserByEmail(details.email) + } + + // exit early if there is still no user and auto creation is disabled + if (!dbUser && requireLocalAccount) { + return authError( + done, + "Email does not yet exist. You must set up your local budibase account first." + ) + } + + // first time creation + if (!dbUser) { + // setup a blank user using the third party id + dbUser = { + _id: userId, + email: details.email, + roles: {}, + tenantId: context.getTenantId(), + } + } + + let ssoUser = await syncUser(dbUser, details) + // never prompt for password reset + ssoUser.forceResetPassword = false + + try { + // don't try to re-save any existing password + delete ssoUser.password + // create or sync the user + ssoUser = (await saveUserFn(ssoUser, { + hashPassword: false, + requirePassword: false, + })) as SSOUser + } catch (err: any) { + return authError(done, "Error saving user", err) + } + + return done(null, ssoUser) +} + +async function getProfilePictureUrl(user: User, details: SSOAuthDetails) { + const pictureUrl = details.profile?._json.picture + if (pictureUrl) { + const response = await fetch(pictureUrl) + if (response.status === 200) { + const type = response.headers.get("content-type") as string + if (type.startsWith("image/")) { + return pictureUrl + } + } + } +} + +/** + * @returns a user that has been sync'd with third party information + */ +async function syncUser(user: User, details: SSOAuthDetails): Promise { + let firstName + let lastName + let pictureUrl + let oauth2 + let thirdPartyProfile + + if (details.profile) { + const profile = details.profile + + if (profile.name) { + const name = profile.name + // first name + if (name.givenName) { + firstName = name.givenName + } + // last name + if (name.familyName) { + lastName = name.familyName + } + } + + pictureUrl = await getProfilePictureUrl(user, details) + + thirdPartyProfile = { + ...profile._json, + } + } + + // oauth tokens for future use + if (details.oauth2) { + oauth2 = { + ...details.oauth2, + } + } + + return { + ...user, + provider: details.provider, + providerType: details.providerType, + firstName, + lastName, + thirdPartyProfile, + pictureUrl, + oauth2, + } +} diff --git a/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts b/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts new file mode 100644 index 0000000000..eb8ffc9b71 --- /dev/null +++ b/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts @@ -0,0 +1,67 @@ +import { generator, structures } from "../../../../../tests" +import { SSOProviderType } from "@budibase/types" + +jest.mock("passport-google-oauth") +const mockStrategy = require("passport-google-oauth").OAuth2Strategy + +jest.mock("../sso") +import * as _sso from "../sso" +const sso = jest.mocked(_sso) + +const mockSaveUserFn = jest.fn() +const mockDone = jest.fn() + +import * as google from "../google" + +describe("google", () => { + describe("strategyFactory", () => { + const googleConfig = structures.sso.googleConfig() + const callbackUrl = generator.url() + + it("should create successfully create a google strategy", async () => { + await google.strategyFactory(googleConfig, callbackUrl) + + const expectedOptions = { + clientID: googleConfig.clientID, + clientSecret: googleConfig.clientSecret, + callbackURL: callbackUrl, + } + + expect(mockStrategy).toHaveBeenCalledWith( + expectedOptions, + expect.anything() + ) + }) + }) + + describe("authenticate", () => { + const details = structures.sso.authDetails() + details.provider = "google" + details.providerType = SSOProviderType.GOOGLE + + const profile = details.profile! + profile.provider = "google" + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("delegates authentication to third party common", async () => { + const authenticate = await google.buildVerifyFn(mockSaveUserFn) + + await authenticate( + details.oauth2.accessToken, + details.oauth2.refreshToken!, + profile, + mockDone + ) + + expect(sso.authenticate).toHaveBeenCalledWith( + details, + true, + mockDone, + mockSaveUserFn + ) + }) + }) +}) diff --git a/packages/backend-core/src/middleware/passport/sso/tests/oidc.spec.ts b/packages/backend-core/src/middleware/passport/sso/tests/oidc.spec.ts new file mode 100644 index 0000000000..a705739bd6 --- /dev/null +++ b/packages/backend-core/src/middleware/passport/sso/tests/oidc.spec.ts @@ -0,0 +1,152 @@ +import { generator, mocks, structures } from "../../../../../tests" +import { + JwtClaims, + OIDCInnerConfig, + SSOAuthDetails, + SSOProviderType, +} from "@budibase/types" +import * as _sso from "../sso" +import * as oidc from "../oidc" + +jest.mock("@techpass/passport-openidconnect") +const mockStrategy = require("@techpass/passport-openidconnect").Strategy + +jest.mock("../sso") +const sso = jest.mocked(_sso) + +const mockSaveUser = jest.fn() +const mockDone = jest.fn() + +describe("oidc", () => { + const callbackUrl = generator.url() + const oidcConfig: OIDCInnerConfig = structures.sso.oidcConfig() + const wellKnownConfig = structures.sso.oidcWellKnownConfig() + + function mockRetrieveWellKnownConfig() { + // mock the request to retrieve the oidc configuration + mocks.fetch.mockReturnValue({ + ok: true, + json: () => wellKnownConfig, + }) + } + + beforeEach(() => { + mockRetrieveWellKnownConfig() + }) + + describe("strategyFactory", () => { + it("should create successfully create an oidc strategy", async () => { + const strategyConfiguration = await oidc.fetchStrategyConfig( + oidcConfig, + callbackUrl + ) + await oidc.strategyFactory(strategyConfiguration, mockSaveUser) + + expect(mocks.fetch).toHaveBeenCalledWith(oidcConfig.configUrl) + + const expectedOptions = { + issuer: wellKnownConfig.issuer, + authorizationURL: wellKnownConfig.authorization_endpoint, + tokenURL: wellKnownConfig.token_endpoint, + userInfoURL: wellKnownConfig.userinfo_endpoint, + clientID: oidcConfig.clientID, + clientSecret: oidcConfig.clientSecret, + callbackURL: callbackUrl, + } + expect(mockStrategy).toHaveBeenCalledWith( + expectedOptions, + expect.anything() + ) + }) + }) + + describe("authenticate", () => { + const details: SSOAuthDetails = structures.sso.authDetails() + details.providerType = SSOProviderType.OIDC + const profile = details.profile! + const issuer = profile.provider + + const sub = generator.string() + const idToken = generator.string() + const params = {} + + let authenticateFn: any + let jwtClaims: JwtClaims + + beforeEach(async () => { + jest.clearAllMocks() + authenticateFn = await oidc.buildVerifyFn(mockSaveUser) + }) + + async function authenticate() { + await authenticateFn( + issuer, + sub, + profile, + jwtClaims, + details.oauth2.accessToken, + details.oauth2.refreshToken, + idToken, + params, + mockDone + ) + } + + it("passes auth details to sso module", async () => { + await authenticate() + + expect(sso.authenticate).toHaveBeenCalledWith( + details, + false, + mockDone, + mockSaveUser + ) + }) + + it("uses JWT email to get email", async () => { + delete profile._json.email + + jwtClaims = { + email: details.email, + } + + await authenticate() + + expect(sso.authenticate).toHaveBeenCalledWith( + details, + false, + mockDone, + mockSaveUser + ) + }) + + it("uses JWT username to get email", async () => { + delete profile._json.email + + jwtClaims = { + email: details.email, + } + + await authenticate() + + expect(sso.authenticate).toHaveBeenCalledWith( + details, + false, + mockDone, + mockSaveUser + ) + }) + + it("uses JWT invalid username to get email", async () => { + delete profile._json.email + + jwtClaims = { + preferred_username: "invalidUsername", + } + + await expect(authenticate()).rejects.toThrow( + "Could not determine user email from profile" + ) + }) + }) +}) diff --git a/packages/backend-core/src/middleware/passport/sso/tests/sso.spec.ts b/packages/backend-core/src/middleware/passport/sso/tests/sso.spec.ts new file mode 100644 index 0000000000..ae42fc01ea --- /dev/null +++ b/packages/backend-core/src/middleware/passport/sso/tests/sso.spec.ts @@ -0,0 +1,196 @@ +import { structures, testEnv, mocks } from "../../../../../tests" +import { SSOAuthDetails, User } from "@budibase/types" + +import { HTTPError } from "../../../../errors" +import * as sso from "../sso" +import * as context from "../../../../context" + +const mockDone = jest.fn() +const mockSaveUser = jest.fn() + +jest.mock("../../../../users") +import * as _users from "../../../../users" +const users = jest.mocked(_users) + +const getErrorMessage = () => { + return mockDone.mock.calls[0][2].message +} + +describe("sso", () => { + describe("authenticate", () => { + beforeEach(() => { + jest.clearAllMocks() + testEnv.singleTenant() + }) + + describe("validation", () => { + const testValidation = async ( + details: SSOAuthDetails, + message: string + ) => { + await sso.authenticate(details, false, mockDone, mockSaveUser) + + expect(mockDone.mock.calls.length).toBe(1) + expect(getErrorMessage()).toContain(message) + } + + it("user id fails", async () => { + const details = structures.sso.authDetails() + details.userId = undefined! + + await testValidation(details, "sso user id required") + }) + + it("email fails", async () => { + const details = structures.sso.authDetails() + details.email = undefined! + + await testValidation(details, "sso user email required") + }) + }) + + function mockGetProfilePicture() { + mocks.fetch.mockReturnValueOnce( + Promise.resolve({ + status: 200, + headers: { get: () => "image/" }, + }) + ) + } + + describe("when the user doesn't exist", () => { + let user: User + let details: SSOAuthDetails + + beforeEach(() => { + users.getById.mockImplementationOnce(() => { + throw new HTTPError("", 404) + }) + mockGetProfilePicture() + + user = structures.users.user() + delete user._rev + delete user._id + + details = structures.sso.authDetails(user) + details.userId = structures.uuid() + }) + + describe("when a local account is required", () => { + it("returns an error message", async () => { + const details = structures.sso.authDetails() + + await sso.authenticate(details, true, mockDone, mockSaveUser) + + expect(mockDone.mock.calls.length).toBe(1) + expect(getErrorMessage()).toContain( + "Email does not yet exist. You must set up your local budibase account first." + ) + }) + }) + + describe("when a local account isn't required", () => { + it("creates and authenticates the user", async () => { + const ssoUser = structures.users.ssoUser({ user, details }) + mockSaveUser.mockReturnValueOnce(ssoUser) + + await sso.authenticate(details, false, mockDone, mockSaveUser) + + // default roles for new user + ssoUser.roles = {} + + // modified external id to match user format + ssoUser._id = "us_" + details.userId + + // new sso user won't have a password + delete ssoUser.password + + // new user isn't saved with rev + delete ssoUser._rev + + // tenant id added + ssoUser.tenantId = context.getTenantId() + + expect(mockSaveUser).toBeCalledWith(ssoUser, { + hashPassword: false, + requirePassword: false, + }) + expect(mockDone).toBeCalledWith(null, ssoUser) + }) + }) + }) + + describe("when the user exists", () => { + let existingUser: User + let details: SSOAuthDetails + + beforeEach(() => { + existingUser = structures.users.user() + existingUser._id = structures.uuid() + details = structures.sso.authDetails(existingUser) + mockGetProfilePicture() + }) + + describe("exists by email", () => { + beforeEach(() => { + users.getById.mockImplementationOnce(() => { + throw new HTTPError("", 404) + }) + users.getGlobalUserByEmail.mockReturnValueOnce( + Promise.resolve(existingUser) + ) + }) + + it("syncs and authenticates the user", async () => { + const ssoUser = structures.users.ssoUser({ + user: existingUser, + details, + }) + mockSaveUser.mockReturnValueOnce(ssoUser) + + await sso.authenticate(details, true, mockDone, mockSaveUser) + + // roles preserved + ssoUser.roles = existingUser.roles + + // existing id preserved + ssoUser._id = existingUser._id + + expect(mockSaveUser).toBeCalledWith(ssoUser, { + hashPassword: false, + requirePassword: false, + }) + expect(mockDone).toBeCalledWith(null, ssoUser) + }) + }) + + describe("exists by id", () => { + beforeEach(() => { + users.getById.mockReturnValueOnce(Promise.resolve(existingUser)) + }) + + it("syncs and authenticates the user", async () => { + const ssoUser = structures.users.ssoUser({ + user: existingUser, + details, + }) + mockSaveUser.mockReturnValueOnce(ssoUser) + + await sso.authenticate(details, true, mockDone, mockSaveUser) + + // roles preserved + ssoUser.roles = existingUser.roles + + // existing id preserved + ssoUser._id = existingUser._id + + expect(mockSaveUser).toBeCalledWith(ssoUser, { + hashPassword: false, + requirePassword: false, + }) + expect(mockDone).toBeCalledWith(null, ssoUser) + }) + }) + }) + }) +}) diff --git a/packages/backend-core/src/middleware/passport/tests/google.spec.js b/packages/backend-core/src/middleware/passport/tests/google.spec.js deleted file mode 100644 index c5580ea309..0000000000 --- a/packages/backend-core/src/middleware/passport/tests/google.spec.js +++ /dev/null @@ -1,79 +0,0 @@ -// Mock data - -const { data } = require("./utilities/mock-data") - -const TENANT_ID = "default" - -const googleConfig = { - clientID: data.clientID, - clientSecret: data.clientSecret, -} - -const profile = { - id: "mockId", - _json: { - email : data.email - }, - provider: "google" -} - -const user = data.buildThirdPartyUser("google", "google", profile) - -describe("google", () => { - describe("strategyFactory", () => { - // mock passport strategy factory - jest.mock("passport-google-oauth") - const mockStrategy = require("passport-google-oauth").OAuth2Strategy - - it("should create successfully create a google strategy", async () => { - const google = require("../google") - - const callbackUrl = `/api/global/auth/${TENANT_ID}/google/callback` - await google.strategyFactory(googleConfig, callbackUrl) - - const expectedOptions = { - clientID: googleConfig.clientID, - clientSecret: googleConfig.clientSecret, - callbackURL: callbackUrl, - } - - expect(mockStrategy).toHaveBeenCalledWith( - expectedOptions, - expect.anything() - ) - }) - }) - - describe("authenticate", () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - // mock third party common authentication - jest.mock("../third-party-common") - const authenticateThirdParty = require("../third-party-common").authenticateThirdParty - - // mock the passport callback - const mockDone = jest.fn() - - it("delegates authentication to third party common", async () => { - const google = require("../google") - const mockSaveUserFn = jest.fn() - const authenticate = await google.buildVerifyFn(mockSaveUserFn) - - await authenticate( - data.accessToken, - data.refreshToken, - profile, - mockDone - ) - - expect(authenticateThirdParty).toHaveBeenCalledWith( - user, - true, - mockDone, - mockSaveUserFn) - }) - }) -}) - diff --git a/packages/backend-core/src/middleware/passport/tests/oidc.spec.js b/packages/backend-core/src/middleware/passport/tests/oidc.spec.js deleted file mode 100644 index 4c8aa94ddf..0000000000 --- a/packages/backend-core/src/middleware/passport/tests/oidc.spec.js +++ /dev/null @@ -1,144 +0,0 @@ -// Mock data -const mockFetch = require("node-fetch") -const { data } = require("./utilities/mock-data") -const issuer = "mockIssuer" -const sub = "mockSub" -const profile = { - id: "mockId", - _json: { - email : data.email - } -} -let jwtClaims = {} -const idToken = "mockIdToken" -const params = {} - -const callbackUrl = "http://somecallbackurl" - -// response from .well-known/openid-configuration -const oidcConfigUrlResponse = { - issuer: issuer, - authorization_endpoint: "mockAuthorizationEndpoint", - token_endpoint: "mockTokenEndpoint", - userinfo_endpoint: "mockUserInfoEndpoint" -} - -const oidcConfig = { - configUrl: "http://someconfigurl", - clientID: data.clientID, - clientSecret: data.clientSecret, -} - -const user = data.buildThirdPartyUser(issuer, "oidc", profile) - -describe("oidc", () => { - describe("strategyFactory", () => { - // mock passport strategy factory - jest.mock("@techpass/passport-openidconnect") - const mockStrategy = require("@techpass/passport-openidconnect").Strategy - - // mock the request to retrieve the oidc configuration - mockFetch.mockReturnValue({ - ok: true, - json: () => oidcConfigUrlResponse - }) - - it("should create successfully create an oidc strategy", async () => { - const oidc = require("../oidc") - const enrichedConfig = await oidc.fetchStrategyConfig(oidcConfig, callbackUrl) - await oidc.strategyFactory(enrichedConfig, callbackUrl) - - expect(mockFetch).toHaveBeenCalledWith(oidcConfig.configUrl) - - const expectedOptions = { - issuer: oidcConfigUrlResponse.issuer, - authorizationURL: oidcConfigUrlResponse.authorization_endpoint, - tokenURL: oidcConfigUrlResponse.token_endpoint, - userInfoURL: oidcConfigUrlResponse.userinfo_endpoint, - clientID: oidcConfig.clientID, - clientSecret: oidcConfig.clientSecret, - callbackURL: callbackUrl, - } - expect(mockStrategy).toHaveBeenCalledWith( - expectedOptions, - expect.anything() - ) - }) - }) - - describe("authenticate", () => { - afterEach(() => { - jest.clearAllMocks() - }); - - // mock third party common authentication - jest.mock("../third-party-common") - const authenticateThirdParty = require("../third-party-common").authenticateThirdParty - - // mock the passport callback - const mockDone = jest.fn() - const mockSaveUserFn = jest.fn() - - async function doAuthenticate() { - const oidc = require("../oidc") - const authenticate = await oidc.buildVerifyFn(mockSaveUserFn) - - await authenticate( - issuer, - sub, - profile, - jwtClaims, - data.accessToken, - data.refreshToken, - idToken, - params, - mockDone - ) - } - - async function doTest() { - await doAuthenticate() - - expect(authenticateThirdParty).toHaveBeenCalledWith( - user, - false, - mockDone, - mockSaveUserFn, - ) - } - - it("delegates authentication to third party common", async () => { - await doTest() - }) - - it("uses JWT email to get email", async () => { - delete profile._json.email - jwtClaims = { - email : "mock@budibase.com" - } - - await doTest() - }) - - it("uses JWT username to get email", async () => { - delete profile._json.email - jwtClaims = { - preferred_username : "mock@budibase.com" - } - - await doTest() - }) - - it("uses JWT invalid username to get email", async () => { - delete profile._json.email - - jwtClaims = { - preferred_username : "invalidUsername" - } - - await expect(doAuthenticate()).rejects.toThrow("Could not determine user email from profile"); - }) - - }) -}) - diff --git a/packages/backend-core/src/middleware/passport/tests/third-party-common.seq.spec.js b/packages/backend-core/src/middleware/passport/tests/third-party-common.seq.spec.js deleted file mode 100644 index d377d602f1..0000000000 --- a/packages/backend-core/src/middleware/passport/tests/third-party-common.seq.spec.js +++ /dev/null @@ -1,178 +0,0 @@ -require("../../../../tests") -const { authenticateThirdParty } = require("../third-party-common") -const { data } = require("./utilities/mock-data") -const { DEFAULT_TENANT_ID } = require("../../../constants") - -const { generateGlobalUserID } = require("../../../db/utils") -const { newid } = require("../../../utils") -const { doWithGlobalDB, doInTenant } = require("../../../tenancy") - -const done = jest.fn() - -const getErrorMessage = () => { - return done.mock.calls[0][2].message -} - -const saveUser = async (user) => { - return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { - return await db.put(user) - }) -} - -function authenticate(user, requireLocal, saveFn) { - return doInTenant(DEFAULT_TENANT_ID, () => { - return authenticateThirdParty(user, requireLocal, done, saveFn) - }) -} - -describe("third party common", () => { - describe("authenticateThirdParty", () => { - let thirdPartyUser - - beforeEach(() => { - thirdPartyUser = data.buildThirdPartyUser() - }) - - afterEach(async () => { - return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { - jest.clearAllMocks() - await db.destroy() - }) - }) - - describe("validation", () => { - const testValidation = async (message) => { - await authenticate(thirdPartyUser, false, saveUser) - expect(done.mock.calls.length).toBe(1) - expect(getErrorMessage()).toContain(message) - } - - it("provider fails", async () => { - delete thirdPartyUser.provider - await testValidation("third party user provider required") - }) - - it("user id fails", async () => { - delete thirdPartyUser.userId - await testValidation("third party user id required") - }) - - it("email fails", async () => { - delete thirdPartyUser.email - await testValidation("third party user email required") - }) - }) - - const expectUserIsAuthenticated = () => { - const user = done.mock.calls[0][1] - expect(user).toBeDefined() - expect(user._id).toBeDefined() - expect(user._rev).toBeDefined() - expect(user.token).toBeDefined() - return user - } - - const expectUserIsSynced = (user, thirdPartyUser) => { - expect(user.provider).toBe(thirdPartyUser.provider) - expect(user.firstName).toBe(thirdPartyUser.profile.name.givenName) - expect(user.lastName).toBe(thirdPartyUser.profile.name.familyName) - expect(user.thirdPartyProfile).toStrictEqual(thirdPartyUser.profile._json) - expect(user.oauth2).toStrictEqual(thirdPartyUser.oauth2) - } - - describe("when the user doesn't exist", () => { - describe("when a local account is required", () => { - it("returns an error message", async () => { - await authenticate(thirdPartyUser, true, saveUser) - expect(done.mock.calls.length).toBe(1) - expect(getErrorMessage()).toContain("Email does not yet exist. You must set up your local budibase account first.") - }) - }) - - describe("when a local account isn't required", () => { - it("creates and authenticates the user", async () => { - await authenticate(thirdPartyUser, false, saveUser) - const user = expectUserIsAuthenticated() - expectUserIsSynced(user, thirdPartyUser) - expect(user.roles).toStrictEqual({}) - }) - }) - }) - - describe("when the user exists", () => { - let dbUser - let id - let email - - const createUser = async () => { - return doWithGlobalDB(DEFAULT_TENANT_ID, async db => { - dbUser = { - _id: id, - email: email, - } - const response = await db.put(dbUser) - dbUser._rev = response.rev - return dbUser - }) - } - - const expectUserIsUpdated = (user) => { - // id is unchanged - expect(user._id).toBe(id) - // user is updated - expect(user._rev).not.toBe(dbUser._rev) - } - - describe("exists by email", () => { - beforeEach(async () => { - id = generateGlobalUserID(newid()) // random id - email = thirdPartyUser.email // matching email - await createUser() - }) - - it("syncs and authenticates the user", async () => { - await authenticate(thirdPartyUser, true, saveUser) - - const user = expectUserIsAuthenticated() - expectUserIsSynced(user, thirdPartyUser) - expectUserIsUpdated(user) - }) - }) - - describe("exists by email with different casing", () => { - beforeEach(async () => { - id = generateGlobalUserID(newid()) // random id - email = thirdPartyUser.email.toUpperCase() // matching email except for casing - await createUser() - }) - - it("syncs and authenticates the user", async () => { - await authenticate(thirdPartyUser, true, saveUser) - - const user = expectUserIsAuthenticated() - expectUserIsSynced(user, thirdPartyUser) - expectUserIsUpdated(user) - expect(user.email).toBe(thirdPartyUser.email.toUpperCase()) - }) - }) - - - describe("exists by id", () => { - beforeEach(async () => { - id = generateGlobalUserID(thirdPartyUser.userId) // matching id - email = "test@test.com" // random email - await createUser() - }) - - it("syncs and authenticates the user", async () => { - await authenticate(thirdPartyUser, true, saveUser) - - const user = expectUserIsAuthenticated() - expectUserIsSynced(user, thirdPartyUser) - expectUserIsUpdated(user) - }) - }) - }) - }) -}) - diff --git a/packages/backend-core/src/middleware/passport/tests/utilities/mock-data.js b/packages/backend-core/src/middleware/passport/tests/utilities/mock-data.js deleted file mode 100644 index 00ae82e47e..0000000000 --- a/packages/backend-core/src/middleware/passport/tests/utilities/mock-data.js +++ /dev/null @@ -1,54 +0,0 @@ -// Mock Data - -const mockClientID = "mockClientID" -const mockClientSecret = "mockClientSecret" - -const mockEmail = "mock@budibase.com" -const mockAccessToken = "mockAccessToken" -const mockRefreshToken = "mockRefreshToken" - -const mockProvider = "mockProvider" -const mockProviderType = "mockProviderType" - -const mockProfile = { - id: "mockId", - name: { - givenName: "mockGivenName", - familyName: "mockFamilyName", - }, - _json: { - email: mockEmail, - }, -} - -const buildOauth2 = ( - accessToken = mockAccessToken, - refreshToken = mockRefreshToken -) => ({ - accessToken: accessToken, - refreshToken: refreshToken, -}) - -const buildThirdPartyUser = ( - provider = mockProvider, - providerType = mockProviderType, - profile = mockProfile, - email = mockEmail, - oauth2 = buildOauth2() -) => ({ - provider: provider, - providerType: providerType, - userId: profile.id, - profile: profile, - email: email, - oauth2: oauth2, -}) - -exports.data = { - clientID: mockClientID, - clientSecret: mockClientSecret, - email: mockEmail, - accessToken: mockAccessToken, - refreshToken: mockRefreshToken, - buildThirdPartyUser, -} diff --git a/packages/backend-core/src/middleware/passport/third-party-common.ts b/packages/backend-core/src/middleware/passport/third-party-common.ts deleted file mode 100644 index 9d7b93f370..0000000000 --- a/packages/backend-core/src/middleware/passport/third-party-common.ts +++ /dev/null @@ -1,177 +0,0 @@ -import env from "../../environment" -import { generateGlobalUserID } from "../../db" -import { authError } from "./utils" -import { newid } from "../../utils" -import { createASession } from "../../security/sessions" -import * as users from "../../users" -import { getGlobalDB, getTenantId } from "../../tenancy" -import fetch from "node-fetch" -import { ThirdPartyUser } from "@budibase/types" -const jwt = require("jsonwebtoken") - -type SaveUserOpts = { - requirePassword?: boolean - hashPassword?: boolean - currentUserId?: string -} - -export type SaveUserFunction = ( - user: ThirdPartyUser, - opts: SaveUserOpts -) => Promise - -/** - * Common authentication logic for third parties. e.g. OAuth, OIDC. - */ -export async function authenticateThirdParty( - thirdPartyUser: ThirdPartyUser, - requireLocalAccount: boolean = true, - done: Function, - saveUserFn?: SaveUserFunction -) { - if (!saveUserFn) { - throw new Error("Save user function must be provided") - } - if (!thirdPartyUser.provider) { - return authError(done, "third party user provider required") - } - if (!thirdPartyUser.userId) { - return authError(done, "third party user id required") - } - if (!thirdPartyUser.email) { - return authError(done, "third party user email required") - } - - // use the third party id - const userId = generateGlobalUserID(thirdPartyUser.userId) - const db = getGlobalDB() - - let dbUser - - // try to load by id - try { - dbUser = await db.get(userId) - } catch (err: any) { - // abort when not 404 error - if (!err.status || err.status !== 404) { - return authError( - done, - "Unexpected error when retrieving existing user", - err - ) - } - } - - // fallback to loading by email - if (!dbUser) { - dbUser = await users.getGlobalUserByEmail(thirdPartyUser.email) - } - - // exit early if there is still no user and auto creation is disabled - if (!dbUser && requireLocalAccount) { - return authError( - done, - "Email does not yet exist. You must set up your local budibase account first." - ) - } - - // first time creation - if (!dbUser) { - // setup a blank user using the third party id - dbUser = { - _id: userId, - email: thirdPartyUser.email, - roles: {}, - } - } - - dbUser = await syncUser(dbUser, thirdPartyUser) - - // never prompt for password reset - dbUser.forceResetPassword = false - - // create or sync the user - try { - await saveUserFn(dbUser, { hashPassword: false, requirePassword: false }) - } catch (err: any) { - return authError(done, "Error saving user", err) - } - - // now that we're sure user exists, load them from the db - dbUser = await db.get(dbUser._id) - - // authenticate - const sessionId = newid() - const tenantId = getTenantId() - await createASession(dbUser._id, { sessionId, tenantId }) - - dbUser.token = jwt.sign( - { - userId: dbUser._id, - sessionId, - }, - env.JWT_SECRET - ) - - return done(null, dbUser) -} - -async function syncProfilePicture( - user: ThirdPartyUser, - thirdPartyUser: ThirdPartyUser -) { - const pictureUrl = thirdPartyUser.profile?._json.picture - if (pictureUrl) { - const response = await fetch(pictureUrl) - - if (response.status === 200) { - const type = response.headers.get("content-type") as string - if (type.startsWith("image/")) { - user.pictureUrl = pictureUrl - } - } - } - - return user -} - -/** - * @returns a user that has been sync'd with third party information - */ -async function syncUser(user: ThirdPartyUser, thirdPartyUser: ThirdPartyUser) { - // provider - user.provider = thirdPartyUser.provider - user.providerType = thirdPartyUser.providerType - - if (thirdPartyUser.profile) { - const profile = thirdPartyUser.profile - - if (profile.name) { - const name = profile.name - // first name - if (name.givenName) { - user.firstName = name.givenName - } - // last name - if (name.familyName) { - user.lastName = name.familyName - } - } - - user = await syncProfilePicture(user, thirdPartyUser) - - // profile - user.thirdPartyProfile = { - ...profile._json, - } - } - - // oauth tokens for future use - if (thirdPartyUser.oauth2) { - user.oauth2 = { - ...thirdPartyUser.oauth2, - } - } - - return user -} diff --git a/packages/backend-core/src/users.ts b/packages/backend-core/src/users.ts index 1720a79a83..ef76af390d 100644 --- a/packages/backend-core/src/users.ts +++ b/packages/backend-core/src/users.ts @@ -8,6 +8,7 @@ import { } from "./db" import { BulkDocsResponse, User } from "@budibase/types" import { getGlobalDB } from "./context" +import * as context from "./context" export const bulkGetGlobalUsersById = async (userIds: string[]) => { const db = getGlobalDB() @@ -24,6 +25,11 @@ export const bulkUpdateGlobalUsers = async (users: User[]) => { return (await db.bulkDocs(users)) as BulkDocsResponse } +export async function getById(id: string): Promise { + const db = context.getGlobalDB() + return db.get(id) +} + /** * Given an email address this will use a view to search through * all the users to find one with this email address. diff --git a/packages/backend-core/src/utils/utils.ts b/packages/backend-core/src/utils/utils.ts index c608686431..3731e134ad 100644 --- a/packages/backend-core/src/utils/utils.ts +++ b/packages/backend-core/src/utils/utils.ts @@ -2,23 +2,15 @@ import { getAllApps, queryGlobalView } from "../db" import { options } from "../middleware/passport/jwt" import { Header, - Cookie, MAX_VALID_DATE, DocumentType, SEPARATOR, ViewName, } from "../constants" import env from "../environment" -import * as userCache from "../cache/user" -import { getSessionsForUser, invalidateSessions } from "../security/sessions" -import * as events from "../events" import * as tenancy from "../tenancy" -import { - App, - Ctx, - PlatformLogoutOpts, - TenantResolutionStrategy, -} from "@budibase/types" +import * as context from "../context" +import { App, Ctx, TenantResolutionStrategy } from "@budibase/types" import { SetOption } from "cookies" const jwt = require("jsonwebtoken") @@ -38,7 +30,7 @@ export async function resolveAppUrl(ctx: Ctx) { const appUrl = ctx.path.split("/")[2] let possibleAppUrl = `/${appUrl.toLowerCase()}` - let tenantId: string | null = tenancy.getTenantId() + let tenantId: string | null = context.getTenantId() if (env.MULTI_TENANCY) { // always use the tenant id from the subdomain in multi tenancy // this ensures the logged-in user tenant id doesn't overwrite @@ -49,7 +41,7 @@ export async function resolveAppUrl(ctx: Ctx) { } // search prod apps for a url that matches - const apps: App[] = await tenancy.doInTenant(tenantId, () => + const apps: App[] = await context.doInTenant(tenantId, () => getAllApps({ dev: false }) ) const app = apps.filter( @@ -222,35 +214,6 @@ export async function getBuildersCount() { return builders.length } -/** - * Logs a user out from budibase. Re-used across account portal and builder. - */ -export async function platformLogout(opts: PlatformLogoutOpts) { - const ctx = opts.ctx - const userId = opts.userId - const keepActiveSession = opts.keepActiveSession - - if (!ctx) throw new Error("Koa context must be supplied to logout.") - - const currentSession = getCookie(ctx, Cookie.Auth) - let sessions = await getSessionsForUser(userId) - - if (keepActiveSession) { - sessions = sessions.filter( - session => session.sessionId !== currentSession.sessionId - ) - } else { - // clear cookies - clearCookie(ctx, Cookie.Auth) - clearCookie(ctx, Cookie.CurrentApp) - } - - const sessionIds = sessions.map(({ sessionId }) => sessionId) - await invalidateSessions(userId, { sessionIds, reason: "logout" }) - await events.auth.logout() - await userCache.invalidateUser(userId) -} - export function timeout(timeMs: number) { return new Promise(resolve => setTimeout(resolve, timeMs)) } diff --git a/packages/backend-core/tests/utilities/mocks/accounts.ts b/packages/backend-core/tests/utilities/mocks/accounts.ts deleted file mode 100644 index e40d32b276..0000000000 --- a/packages/backend-core/tests/utilities/mocks/accounts.ts +++ /dev/null @@ -1,13 +0,0 @@ -const mockGetAccount = jest.fn() -const mockGetAccountByTenantId = jest.fn() -const mockGetStatus = jest.fn() - -jest.mock("../../../src/cloud/accounts", () => ({ - getAccount: mockGetAccount, - getAccountByTenantId: mockGetAccountByTenantId, - getStatus: mockGetStatus, -})) - -export const getAccount = mockGetAccount -export const getAccountByTenantId = mockGetAccountByTenantId -export const getStatus = mockGetStatus diff --git a/packages/backend-core/tests/utilities/mocks/index.ts b/packages/backend-core/tests/utilities/mocks/index.ts index 401fd7d7a7..f5f45c0342 100644 --- a/packages/backend-core/tests/utilities/mocks/index.ts +++ b/packages/backend-core/tests/utilities/mocks/index.ts @@ -1,4 +1,7 @@ -export * as accounts from "./accounts" +jest.mock("../../../src/accounts") +import * as _accounts from "../../../src/accounts" +export const accounts = jest.mocked(_accounts) + export * as date from "./date" export * as licenses from "./licenses" export { default as fetch } from "./fetch" diff --git a/packages/backend-core/tests/utilities/structures/accounts.ts b/packages/backend-core/tests/utilities/structures/accounts.ts index f1718aecc0..6bfeedf196 100644 --- a/packages/backend-core/tests/utilities/structures/accounts.ts +++ b/packages/backend-core/tests/utilities/structures/accounts.ts @@ -1,6 +1,15 @@ import { generator, uuid } from "." import * as db from "../../../src/db/utils" -import { Account, AuthType, CloudAccount, Hosting } from "@budibase/types" +import { + Account, + AccountSSOProvider, + AccountSSOProviderType, + AuthType, + CloudAccount, + Hosting, + SSOAccount, +} from "@budibase/types" +import _ from "lodash" export const account = (): Account => { return { @@ -27,3 +36,28 @@ export const cloudAccount = (): CloudAccount => { budibaseUserId: db.generateGlobalUserID(), } } + +function providerType(): AccountSSOProviderType { + return _.sample( + Object.values(AccountSSOProviderType) + ) as AccountSSOProviderType +} + +function provider(): AccountSSOProvider { + return _.sample(Object.values(AccountSSOProvider)) as AccountSSOProvider +} + +export function ssoAccount(): SSOAccount { + return { + ...cloudAccount(), + authType: AuthType.SSO, + oauth2: { + accessToken: generator.string(), + refreshToken: generator.string(), + }, + pictureUrl: generator.url(), + provider: provider(), + providerType: providerType(), + thirdPartyProfile: {}, + } +} diff --git a/packages/backend-core/tests/utilities/structures/index.ts b/packages/backend-core/tests/utilities/structures/index.ts index e74751e479..d0073ba851 100644 --- a/packages/backend-core/tests/utilities/structures/index.ts +++ b/packages/backend-core/tests/utilities/structures/index.ts @@ -5,8 +5,10 @@ export const generator = new Chance() export * as accounts from "./accounts" export * as apps from "./apps" +export * as db from "./db" export * as koa from "./koa" export * as licenses from "./licenses" export * as plugins from "./plugins" +export * as sso from "./sso" export * as tenant from "./tenants" -export * as db from "./db" +export * as users from "./users" diff --git a/packages/backend-core/tests/utilities/structures/sso.ts b/packages/backend-core/tests/utilities/structures/sso.ts new file mode 100644 index 0000000000..ad5e8e87ef --- /dev/null +++ b/packages/backend-core/tests/utilities/structures/sso.ts @@ -0,0 +1,100 @@ +import { + GoogleInnerConfig, + JwtClaims, + OIDCInnerConfig, + OIDCWellKnownConfig, + SSOAuthDetails, + SSOProfile, + SSOProviderType, + User, +} from "@budibase/types" +import { uuid, generator, users, email } from "./index" +import _ from "lodash" + +export function providerType(): SSOProviderType { + return _.sample(Object.values(SSOProviderType)) as SSOProviderType +} + +export function ssoProfile(user?: User): SSOProfile { + if (!user) { + user = users.user() + } + return { + id: user._id!, + name: { + givenName: user.firstName, + familyName: user.lastName, + }, + _json: { + email: user.email, + picture: "http://test.com", + }, + provider: generator.string(), + } +} + +export function authDetails(user?: User): SSOAuthDetails { + if (!user) { + user = users.user() + } + + const userId = user._id || uuid() + const provider = generator.string() + + const profile = ssoProfile(user) + profile.provider = provider + profile.id = userId + + return { + email: user.email, + oauth2: { + refreshToken: generator.string(), + accessToken: generator.string(), + }, + profile, + provider, + providerType: providerType(), + userId, + } +} + +// OIDC + +export function oidcConfig(): OIDCInnerConfig { + return { + uuid: uuid(), + activated: true, + logo: "", + name: generator.string(), + configUrl: "http://someconfigurl", + clientID: generator.string(), + clientSecret: generator.string(), + } +} + +// response from .well-known/openid-configuration +export function oidcWellKnownConfig(): OIDCWellKnownConfig { + return { + issuer: generator.string(), + authorization_endpoint: generator.url(), + token_endpoint: generator.url(), + userinfo_endpoint: generator.url(), + } +} + +export function jwtClaims(): JwtClaims { + return { + email: email(), + preferred_username: email(), + } +} + +// GOOGLE + +export function googleConfig(): GoogleInnerConfig { + return { + activated: true, + clientID: generator.string(), + clientSecret: generator.string(), + } +} diff --git a/packages/backend-core/tests/utilities/structures/users.ts b/packages/backend-core/tests/utilities/structures/users.ts new file mode 100644 index 0000000000..332c27ca12 --- /dev/null +++ b/packages/backend-core/tests/utilities/structures/users.ts @@ -0,0 +1,70 @@ +import { generator } from "../" +import { + AdminUser, + BuilderUser, + SSOAuthDetails, + SSOUser, + User, +} from "@budibase/types" +import { v4 as uuid } from "uuid" +import * as sso from "./sso" + +export const newEmail = () => { + return `${uuid()}@test.com` +} + +export const user = (userProps?: any): User => { + return { + email: newEmail(), + password: "test", + roles: { app_test: "admin" }, + firstName: generator.first(), + lastName: generator.last(), + pictureUrl: "http://test.com", + ...userProps, + } +} + +export const adminUser = (userProps?: any): AdminUser => { + return { + ...user(userProps), + admin: { + global: true, + }, + builder: { + global: true, + }, + } +} + +export const builderUser = (userProps?: any): BuilderUser => { + return { + ...user(userProps), + builder: { + global: true, + }, + } +} + +export function ssoUser( + opts: { user?: any; details?: SSOAuthDetails } = {} +): SSOUser { + const base = user(opts.user) + delete base.password + + if (!opts.details) { + opts.details = sso.authDetails(base) + } + + return { + ...base, + forceResetPassword: false, + oauth2: opts.details?.oauth2, + provider: opts.details?.provider!, + providerType: opts.details?.providerType!, + thirdPartyProfile: { + email: base.email, + picture: base.pictureUrl, + }, + } +} diff --git a/packages/builder/src/pages/builder/portal/_components/UserDropdown.svelte b/packages/builder/src/pages/builder/portal/_components/UserDropdown.svelte index d396edd4e2..935d69812f 100644 --- a/packages/builder/src/pages/builder/portal/_components/UserDropdown.svelte +++ b/packages/builder/src/pages/builder/portal/_components/UserDropdown.svelte @@ -30,9 +30,11 @@ My profile themeModal.show()}>Theme - updatePasswordModal.show()}> - Update password - + {#if !$auth.isSSO} + updatePasswordModal.show()}> + Update password + + {/if} apiKeyModal.show()}> View API key diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index b14e3420cc..1c26273a8d 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -81,6 +81,7 @@ let user let loaded = false + $: isSSO = !!user?.provider $: readonly = !$auth.isAdmin $: fullName = user?.firstName ? user?.firstName + " " + user?.lastName : "" $: privileged = user?.admin?.global || user?.builder?.global @@ -246,9 +247,11 @@ - - Force password reset - + {#if !isSSO} + + Force password reset + + {/if} Delete diff --git a/packages/builder/src/stores/portal/auth.js b/packages/builder/src/stores/portal/auth.js index b10cd05e00..d039bb6eec 100644 --- a/packages/builder/src/stores/portal/auth.js +++ b/packages/builder/src/stores/portal/auth.js @@ -41,6 +41,7 @@ export function createAuthStore() { initials, isAdmin, isBuilder, + isSSO: !!$store.user?.provider, } }) diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 9a0d69e352..cf4eef75a9 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -817,7 +817,6 @@ "type": "string", "enum": [ "string", - "barcodeqr", "longform", "options", "number", @@ -829,7 +828,8 @@ "formula", "auto", "json", - "internal" + "internal", + "barcodeqr" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1021,7 +1021,6 @@ "type": "string", "enum": [ "string", - "barcodeqr", "longform", "options", "number", @@ -1033,7 +1032,8 @@ "formula", "auto", "json", - "internal" + "internal", + "barcodeqr" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1236,7 +1236,6 @@ "type": "string", "enum": [ "string", - "barcodeqr", "longform", "options", "number", @@ -1248,7 +1247,8 @@ "formula", "auto", "json", - "internal" + "internal", + "barcodeqr" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 69e44d881c..414efe7adb 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -603,7 +603,6 @@ components: type: string enum: - string - - barcodeqr - longform - options - number @@ -616,6 +615,7 @@ components: - auto - json - internal + - barcodeqr description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -766,7 +766,6 @@ components: type: string enum: - string - - barcodeqr - longform - options - number @@ -779,6 +778,7 @@ components: - auto - json - internal + - barcodeqr description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -936,7 +936,6 @@ components: type: string enum: - string - - barcodeqr - longform - options - number @@ -949,6 +948,7 @@ components: - auto - json - internal + - barcodeqr description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: diff --git a/packages/server/src/integrations/tests/couchdb.spec.ts b/packages/server/src/integrations/tests/couchdb.spec.ts index 0d744cd343..66735d7b74 100644 --- a/packages/server/src/integrations/tests/couchdb.spec.ts +++ b/packages/server/src/integrations/tests/couchdb.spec.ts @@ -1,5 +1,3 @@ -import { DatabaseWithConnection } from "@budibase/backend-core/src/db" - jest.mock("@budibase/backend-core", () => { const core = jest.requireActual("@budibase/backend-core") return { diff --git a/packages/types/src/api/account/index.ts b/packages/types/src/api/account/index.ts index 0cbc487bcc..4be610d1b3 100644 --- a/packages/types/src/api/account/index.ts +++ b/packages/types/src/api/account/index.ts @@ -1,2 +1,3 @@ export * from "./user" export * from "./license" +export * from "./status" diff --git a/packages/types/src/api/account/status.ts b/packages/types/src/api/account/status.ts new file mode 100644 index 0000000000..f6a0db7a5e --- /dev/null +++ b/packages/types/src/api/account/status.ts @@ -0,0 +1,7 @@ +export interface HealthStatusResponse { + passing: boolean + checks: { + login: boolean + search: boolean + } +} diff --git a/packages/types/src/api/web/auth.ts b/packages/types/src/api/web/auth.ts new file mode 100644 index 0000000000..e31a151c48 --- /dev/null +++ b/packages/types/src/api/web/auth.ts @@ -0,0 +1,25 @@ +export interface LoginRequest { + username: string + password: string +} + +export interface PasswordResetRequest { + email: string +} + +export interface PasswordResetUpdateRequest { + resetCode: string + password: string +} + +export interface UpdateSelfRequest { + firstName?: string + lastName?: string + password?: string + forceResetPassword?: boolean +} + +export interface UpdateSelfResponse { + _id: string + _rev: string +} diff --git a/packages/types/src/api/web/index.ts b/packages/types/src/api/web/index.ts index 9688a89c7b..8ed5b0aad4 100644 --- a/packages/types/src/api/web/index.ts +++ b/packages/types/src/api/web/index.ts @@ -1,4 +1,5 @@ export * from "./analytics" +export * from "./auth" export * from "./user" export * from "./errors" export * from "./schedule" diff --git a/packages/types/src/api/web/user.ts b/packages/types/src/api/web/user.ts index 6acaf6912d..a435808f7e 100644 --- a/packages/types/src/api/web/user.ts +++ b/packages/types/src/api/web/user.ts @@ -1,6 +1,6 @@ import { User } from "../../documents" -export interface CreateUserResponse { +export interface SaveUserResponse { _id: string _rev: string email: string @@ -58,6 +58,25 @@ export interface CreateAdminUserRequest { tenantId: string } +export interface CreateAdminUserResponse { + _id: string + _rev: string + email: string +} + +export interface AcceptUserInviteRequest { + inviteCode: string + password: string + firstName: string + lastName: string +} + +export interface AcceptUserInviteResponse { + _id: string + _rev: string + email: string +} + export interface SyncUserRequest { previousUser?: User } diff --git a/packages/types/src/documents/account/account.ts b/packages/types/src/documents/account/account.ts index a8684f8427..cacdc4e9a2 100644 --- a/packages/types/src/documents/account/account.ts +++ b/packages/types/src/documents/account/account.ts @@ -79,14 +79,24 @@ export const isSelfHostAccount = (account: Account) => export const isSSOAccount = (account: Account): account is SSOAccount => account.authType === AuthType.SSO -export interface SSOAccount extends Account { - pictureUrl?: string - provider?: string - providerType?: string +export enum AccountSSOProviderType { + GOOGLE = "google", +} + +export enum AccountSSOProvider { + GOOGLE = "google", +} + +export interface AccountSSO { + provider: AccountSSOProvider + providerType: AccountSSOProviderType oauth2?: OAuthTokens + pictureUrl?: string thirdPartyProfile: any // TODO: define what the google profile looks like } +export type SSOAccount = (Account | CloudAccount) & AccountSSO + export enum AuthType { SSO = "sso", PASSWORD = "password", diff --git a/packages/types/src/documents/global/config.ts b/packages/types/src/documents/global/config.ts index 9b05069c9a..99dec534b6 100644 --- a/packages/types/src/documents/global/config.ts +++ b/packages/types/src/documents/global/config.ts @@ -27,15 +27,17 @@ export interface SettingsConfig extends Config { } } -export interface GoogleConfig extends Config { - config: { - clientID: string - clientSecret: string - activated: boolean - } +export interface GoogleInnerConfig { + clientID: string + clientSecret: string + activated: boolean } -export interface OIDCConfiguration { +export interface GoogleConfig extends Config { + config: GoogleInnerConfig +} + +export interface OIDCStrategyConfiguration { issuer: string authorizationURL: string tokenURL: string @@ -45,7 +47,7 @@ export interface OIDCConfiguration { callbackURL: string } -export interface OIDCInnerCfg { +export interface OIDCInnerConfig { configUrl: string clientID: string clientSecret: string @@ -57,10 +59,17 @@ export interface OIDCInnerCfg { export interface OIDCConfig extends Config { config: { - configs: OIDCInnerCfg[] + configs: OIDCInnerConfig[] } } +export interface OIDCWellKnownConfig { + issuer: string + authorization_endpoint: string + token_endpoint: string + userinfo_endpoint: string +} + export const isSettingsConfig = (config: Config): config is SettingsConfig => config.type === ConfigType.SETTINGS diff --git a/packages/types/src/documents/global/user.ts b/packages/types/src/documents/global/user.ts index aef36c3469..2ef13a7412 100644 --- a/packages/types/src/documents/global/user.ts +++ b/packages/types/src/documents/global/user.ts @@ -1,37 +1,44 @@ import { Document } from "../document" -export interface SSOProfile { - id: string - name?: { - givenName?: string - familyName?: string - } - _json: { - email: string - picture: string - } - provider?: string +// SSO + +export interface SSOProfileJson { + email?: string + picture?: string } -export interface ThirdPartyUser extends Document { - thirdPartyProfile?: SSOProfile["_json"] - firstName?: string - lastName?: string - pictureUrl?: string - profile?: SSOProfile - oauth2?: any - provider?: string - providerType?: string - email: string - userId?: string - forceResetPassword?: boolean - userGroups?: string[] +export interface OAuth2 { + accessToken: string + refreshToken?: string } -export interface User extends ThirdPartyUser { +export enum SSOProviderType { + OIDC = "oidc", + GOOGLE = "google", +} + +export interface UserSSO { + provider: string // the individual provider e.g. Okta, Auth0, Google + providerType: SSOProviderType + oauth2?: OAuth2 + thirdPartyProfile?: SSOProfileJson +} + +export type SSOUser = User & UserSSO + +export function isSSOUser(user: User): user is SSOUser { + return !!(user as SSOUser).providerType +} + +// USER + +export interface User extends Document { tenantId: string email: string userId?: string + firstName?: string + lastName?: string + pictureUrl?: string forceResetPassword?: boolean roles: UserRoles builder?: { @@ -44,9 +51,7 @@ export interface User extends ThirdPartyUser { status?: string createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now() dayPassRecordedAt?: string - account?: { - authType: string - } + userGroups?: string[] onboardedAt?: string } @@ -54,7 +59,7 @@ export interface UserRoles { [key: string]: string } -// utility types +// UTILITY TYPES export interface BuilderUser extends User { builder: { diff --git a/packages/types/src/sdk/index.ts b/packages/types/src/sdk/index.ts index f8f9d9cb97..be12d45527 100644 --- a/packages/types/src/sdk/index.ts +++ b/packages/types/src/sdk/index.ts @@ -12,3 +12,5 @@ export * from "./db" export * from "./middleware" export * from "./featureFlag" export * from "./environmentVariables" +export * from "./sso" +export * from "./user" diff --git a/packages/types/src/sdk/sso.ts b/packages/types/src/sdk/sso.ts new file mode 100644 index 0000000000..2141204ccb --- /dev/null +++ b/packages/types/src/sdk/sso.ts @@ -0,0 +1,37 @@ +import { + OAuth2, + SSOProfileJson, + SSOProviderType, + SSOUser, + User, +} from "../documents" +import { SaveUserOpts } from "./user" + +export interface JwtClaims { + preferred_username?: string + email?: string +} + +export interface SSOAuthDetails { + oauth2: OAuth2 + provider: string + providerType: SSOProviderType + userId: string + email?: string + profile?: SSOProfile +} + +export interface SSOProfile { + id: string + name?: { + givenName?: string + familyName?: string + } + _json: SSOProfileJson + provider?: string +} + +export type SaveSSOUserFunction = ( + user: SSOUser, + opts: SaveUserOpts +) => Promise diff --git a/packages/types/src/sdk/user.ts b/packages/types/src/sdk/user.ts new file mode 100644 index 0000000000..1602eeb6c8 --- /dev/null +++ b/packages/types/src/sdk/user.ts @@ -0,0 +1,12 @@ +export interface UpdateSelf { + firstName?: string + lastName?: string + password?: string + forceResetPassword?: boolean +} + +export interface SaveUserOpts { + hashPassword?: boolean + requirePassword?: boolean + currentUserId?: string +} diff --git a/packages/worker/scripts/dev/manage.js b/packages/worker/scripts/dev/manage.js index 01cdef08ff..21a9eab9c6 100644 --- a/packages/worker/scripts/dev/manage.js +++ b/packages/worker/scripts/dev/manage.js @@ -29,6 +29,7 @@ async function init() { SERVICE: "worker-service", DEPLOYMENT_ENVIRONMENT: "development", TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR", + ENABLE_EMAIL_TEST_MODE: 1, } let envFile = "" Object.keys(envFileJson).forEach(key => { diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index 738b67c553..948a98cf3a 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -1,49 +1,55 @@ import { - auth, + auth as authCore, constants, context, db as dbCore, events, tenancy, - users as usersCore, - utils, + utils as utilsCore, } from "@budibase/backend-core" -import { EmailTemplatePurpose } from "../../../constants" -import { isEmailConfigured, sendEmail } from "../../../utilities/email" -import { checkResetPasswordCode } from "../../../utilities/redis" +import { + ConfigType, + User, + Ctx, + LoginRequest, + SSOUser, + PasswordResetRequest, + PasswordResetUpdateRequest, +} from "@budibase/types" import env from "../../../environment" -import sdk from "../../../sdk" -import { ConfigType, User } from "@budibase/types" -const { setCookie, getCookie, clearCookie, hash, platformLogout } = utils +import * as authSdk from "../../../sdk/auth" +import * as userSdk from "../../../sdk/users" + const { Cookie, Header } = constants -const { passport, ssoCallbackUrl, google, oidc } = auth +const { passport, ssoCallbackUrl, google, oidc } = authCore +const { setCookie, getCookie, clearCookie } = utilsCore -export async function googleCallbackUrl(config?: { callbackURL?: string }) { - return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.GOOGLE) -} +// LOGIN / LOGOUT -export async function oidcCallbackUrl(config?: { callbackURL?: string }) { - return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.OIDC) -} - -async function authInternal(ctx: any, user: any, err: any = null, info = null) { +async function passportCallback( + ctx: Ctx, + user: User, + err: any = null, + info: { message: string } | null = null +) { if (err) { console.error("Authentication error") console.error(err) console.trace(err) return ctx.throw(403, info ? info : "Unauthorized") } - if (!user) { console.error("Authentication error - no user provided") return ctx.throw(403, info ? info : "Unauthorized") } + const token = await authSdk.loginUser(user) + // set a cookie for browser access - setCookie(ctx, user.token, Cookie.Auth, { sign: false }) + setCookie(ctx, token, Cookie.Auth, { sign: false }) // set the token in a header as well for APIs - ctx.set(Header.TOKEN, user.token) + ctx.set(Header.TOKEN, token) // get rid of any app cookies on login // have to check test because this breaks cypress if (!env.isTest()) { @@ -51,11 +57,18 @@ async function authInternal(ctx: any, user: any, err: any = null, info = null) { } } -export const authenticate = async (ctx: any, next: any) => { +export const login = async (ctx: Ctx, next: any) => { + const email = ctx.request.body.username + + const user = await userSdk.getUserByEmail(email) + if (user && (await userSdk.isPreventSSOPasswords(user))) { + ctx.throw(400, "SSO user cannot login using password") + } + return passport.authenticate( "local", async (err: any, user: User, info: any) => { - await authInternal(ctx, user, err, info) + await passportCallback(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { await events.auth.login("local") }) @@ -64,6 +77,15 @@ export const authenticate = async (ctx: any, next: any) => { )(ctx, next) } +export const logout = async (ctx: any) => { + if (ctx.user && ctx.user._id) { + await authSdk.logout({ ctx, userId: ctx.user._id }) + } + ctx.body = { message: "User logged out." } +} + +// INIT + export const setInitInfo = (ctx: any) => { const initInfo = ctx.request.body setCookie(ctx, initInfo, Cookie.Init) @@ -79,32 +101,16 @@ export const getInitInfo = (ctx: any) => { } } +// PASSWORD MANAGEMENT + /** * Reset the user password, used as part of a forgotten password flow. */ -export const reset = async (ctx: any) => { +export const reset = async (ctx: Ctx) => { const { email } = ctx.request.body - const configured = await isEmailConfigured() - if (!configured) { - ctx.throw( - 400, - "Please contact your platform administrator, SMTP is not configured." - ) - } - try { - const user = (await usersCore.getGlobalUserByEmail(email)) as User - // only if user exists, don't error though if they don't - if (user) { - await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, { - user, - subject: "{{ company }} platform password reset", - }) - await events.user.passwordResetRequested(user) - } - } catch (err) { - console.log(err) - // don't throw any kind of error to the user, this might give away something - } + + await authSdk.reset(email) + ctx.body = { message: "Please check your email for a reset link.", } @@ -113,32 +119,21 @@ export const reset = async (ctx: any) => { /** * Perform the user password update if the provided reset code is valid. */ -export const resetUpdate = async (ctx: any) => { +export const resetUpdate = async (ctx: Ctx) => { const { resetCode, password } = ctx.request.body try { - const { userId } = await checkResetPasswordCode(resetCode) - const db = tenancy.getGlobalDB() - const user = await db.get(userId) - user.password = await hash(password) - await db.put(user) + await authSdk.resetUpdate(resetCode, password) ctx.body = { message: "password reset successfully.", } - // remove password from the user before sending events - delete user.password - await events.user.passwordReset(user) } catch (err) { - console.error(err) + console.warn(err) + // hide any details of the error for security ctx.throw(400, "Cannot reset password.") } } -export const logout = async (ctx: any) => { - if (ctx.user && ctx.user._id) { - await platformLogout({ ctx, userId: ctx.user._id }) - } - ctx.body = { message: "User logged out." } -} +// DATASOURCE export const datasourcePreAuth = async (ctx: any, next: any) => { const provider = ctx.params.provider @@ -166,6 +161,12 @@ export const datasourceAuth = async (ctx: any, next: any) => { return handler.postAuth(passport, ctx, next) } +// GOOGLE SSO + +export async function googleCallbackUrl(config?: { callbackURL?: string }) { + return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.GOOGLE) +} + /** * The initial call that google authentication makes to take you to the google login screen. * On a successful login, you will be redirected to the googleAuth callback route. @@ -181,7 +182,7 @@ export const googlePreAuth = async (ctx: any, next: any) => { const strategy = await google.strategyFactory( config, callbackUrl, - sdk.users.save + userSdk.save ) return passport.authenticate(strategy, { @@ -191,7 +192,7 @@ export const googlePreAuth = async (ctx: any, next: any) => { })(ctx, next) } -export const googleAuth = async (ctx: any, next: any) => { +export const googleCallback = async (ctx: any, next: any) => { const db = tenancy.getGlobalDB() const config = await dbCore.getScopedConfig(db, { @@ -202,14 +203,14 @@ export const googleAuth = async (ctx: any, next: any) => { const strategy = await google.strategyFactory( config, callbackUrl, - sdk.users.save + userSdk.save ) return passport.authenticate( strategy, { successRedirect: "/", failureRedirect: "/error" }, - async (err: any, user: User, info: any) => { - await authInternal(ctx, user, err, info) + async (err: any, user: SSOUser, info: any) => { + await passportCallback(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { await events.auth.login("google-internal") }) @@ -218,6 +219,12 @@ export const googleAuth = async (ctx: any, next: any) => { )(ctx, next) } +// OIDC SSO + +export async function oidcCallbackUrl(config?: { callbackURL?: string }) { + return ssoCallbackUrl(tenancy.getGlobalDB(), config, ConfigType.OIDC) +} + export const oidcStrategyFactory = async (ctx: any, configId: any) => { const db = tenancy.getGlobalDB() const config = await dbCore.getScopedConfig(db, { @@ -233,7 +240,7 @@ export const oidcStrategyFactory = async (ctx: any, configId: any) => { chosenConfig, callbackUrl ) - return oidc.strategyFactory(enrichedConfig, sdk.users.save) + return oidc.strategyFactory(enrichedConfig, userSdk.save) } /** @@ -265,15 +272,15 @@ export const oidcPreAuth = async (ctx: any, next: any) => { })(ctx, next) } -export const oidcAuth = async (ctx: any, next: any) => { +export const oidcCallback = async (ctx: any, next: any) => { const configId = getCookie(ctx, Cookie.OIDC_CONFIG) const strategy = await oidcStrategyFactory(ctx, configId) return passport.authenticate( strategy, { successRedirect: "/", failureRedirect: "/error" }, - async (err: any, user: any, info: any) => { - await authInternal(ctx, user, err, info) + async (err: any, user: SSOUser, info: any) => { + await passportCallback(ctx, user, err, info) await context.identity.doInUserContext(user, async () => { await events.auth.login("oidc") }) diff --git a/packages/worker/src/api/controllers/global/self.ts b/packages/worker/src/api/controllers/global/self.ts index 06906f1e8e..889a3e6a27 100644 --- a/packages/worker/src/api/controllers/global/self.ts +++ b/packages/worker/src/api/controllers/global/self.ts @@ -1,18 +1,22 @@ -import sdk from "../../../sdk" +import * as userSdk from "../../../sdk/users" import { - events, featureFlags, tenancy, constants, db as dbCore, utils, - cache, encryption, + auth as authCore, } from "@budibase/backend-core" import env from "../../../environment" import { groups } from "@budibase/pro" -const { hash, platformLogout, getCookie, clearCookie, newid } = utils -const { user: userCache } = cache +import { + UpdateSelfRequest, + UpdateSelfResponse, + UpdateSelf, + UserCtx, +} from "@budibase/types" +const { getCookie, clearCookie, newid } = utils function newTestApiKey() { return env.ENCRYPTED_TEST_PUBLIC_API_KEY @@ -93,17 +97,6 @@ const addSessionAttributesToUser = (ctx: any) => { ctx.body.csrfToken = ctx.user.csrfToken } -const sanitiseUserUpdate = (ctx: any) => { - const allowed = ["firstName", "lastName", "password", "forceResetPassword"] - const resp: { [key: string]: any } = {} - for (let [key, value] of Object.entries(ctx.request.body)) { - if (allowed.includes(key)) { - resp[key] = value - } - } - return resp -} - export async function getSelf(ctx: any) { if (!ctx.user) { ctx.throw(403, "User not logged in") @@ -116,7 +109,7 @@ export async function getSelf(ctx: any) { checkCurrentApp(ctx) // get the main body of the user - const user = await sdk.users.getUser(userId) + const user = await userSdk.getUser(userId) ctx.body = await groups.enrichUserRolesFromGroups(user) // add the feature flags for this tenant @@ -126,39 +119,30 @@ export async function getSelf(ctx: any) { addSessionAttributesToUser(ctx) } -export async function updateSelf(ctx: any) { - const db = tenancy.getGlobalDB() - const user = await db.get(ctx.user._id) - let passwordChange = false +export async function updateSelf( + ctx: UserCtx +) { + const body = ctx.request.body + const update: UpdateSelf = { + firstName: body.firstName, + lastName: body.lastName, + password: body.password, + forceResetPassword: body.forceResetPassword, + } - const userUpdateObj = sanitiseUserUpdate(ctx) - if (userUpdateObj.password) { - // changing password - passwordChange = true - userUpdateObj.password = await hash(userUpdateObj.password) + const user = await userSdk.updateSelf(ctx.user._id!, update) + + if (update.password) { // Log all other sessions out apart from the current one - await platformLogout({ + await authCore.platformLogout({ ctx, - userId: ctx.user._id, + userId: ctx.user._id!, keepActiveSession: true, }) } - const response = await db.put({ - ...user, - ...userUpdateObj, - }) - await userCache.invalidateUser(user._id) ctx.body = { - _id: response.id, - _rev: response.rev, - } - - // remove the old password from the user before sending events - user._rev = response.rev - delete user.password - await events.user.updated(user) - if (passwordChange) { - await events.user.passwordUpdated(user) + _id: user._id!, + _rev: user._rev!, } } diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 43ec23eade..c722d27faa 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -2,15 +2,21 @@ import { checkInviteCode } from "../../../utilities/redis" import * as userSdk from "../../../sdk/users" import env from "../../../environment" import { + AcceptUserInviteRequest, + AcceptUserInviteResponse, BulkUserRequest, BulkUserResponse, CloudAccount, CreateAdminUserRequest, + CreateAdminUserResponse, + Ctx, InviteUserRequest, InviteUsersRequest, MigrationType, + SaveUserResponse, SearchUsersRequest, User, + UserCtx, } from "@budibase/types" import { accounts, @@ -25,10 +31,18 @@ import { checkAnyUserExists } from "../../../utilities/users" const MAX_USERS_UPLOAD_LIMIT = 1000 -export const save = async (ctx: any) => { +export const save = async (ctx: UserCtx) => { try { const currentUserId = ctx.user._id - ctx.body = await userSdk.save(ctx.request.body, { currentUserId }) + const requestUser = ctx.request.body + + const user = await userSdk.save(requestUser, { currentUserId }) + + ctx.body = { + _id: user._id!, + _rev: user._rev!, + email: user.email, + } } catch (err: any) { ctx.throw(err.status || 400, err) } @@ -71,9 +85,10 @@ const parseBooleanParam = (param: any) => { return !(param && param === "false") } -export const adminUser = async (ctx: any) => { - const { email, password, tenantId } = ctx.request - .body as CreateAdminUserRequest +export const adminUser = async ( + ctx: Ctx +) => { + const { email, password, tenantId } = ctx.request.body if (await platform.tenants.exists(tenantId)) { ctx.throw(403, "Organisation already exists.") @@ -131,7 +146,11 @@ export const adminUser = async (ctx: any) => { } await events.identification.identifyTenantGroup(tenantId, account) - ctx.body = finalUser + ctx.body = { + _id: finalUser._id!, + _rev: finalUser._rev!, + email: finalUser.email, + } } catch (err: any) { ctx.throw(err.status || 400, err) } @@ -236,12 +255,14 @@ export const checkInvite = async (ctx: any) => { } } -export const inviteAccept = async (ctx: any) => { +export const inviteAccept = async ( + ctx: Ctx +) => { const { inviteCode, password, firstName, lastName } = ctx.request.body try { // info is an extension of the user object that was stored by global const { email, info }: any = await checkInviteCode(inviteCode) - ctx.body = await tenancy.doInTenant(info.tenantId, async () => { + const user = await tenancy.doInTenant(info.tenantId, async () => { const saved = await userSdk.save({ firstName, lastName, @@ -254,6 +275,12 @@ export const inviteAccept = async (ctx: any) => { await events.user.inviteAccepted(user) return saved }) + + ctx.body = { + _id: user._id, + _rev: user._rev, + email: user.email, + } } catch (err: any) { if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) { // explicitly re-throw limit exceeded errors diff --git a/packages/worker/src/api/controllers/system/accounts.ts b/packages/worker/src/api/controllers/system/accounts.ts index 0aa5f25785..10b809c0b5 100644 --- a/packages/worker/src/api/controllers/system/accounts.ts +++ b/packages/worker/src/api/controllers/system/accounts.ts @@ -1,21 +1,23 @@ import { Account, AccountMetadata } from "@budibase/types" -import sdk from "../../../sdk" +import * as accounts from "../../../sdk/accounts" export const save = async (ctx: any) => { const account = ctx.request.body as Account let metadata: AccountMetadata = { - _id: sdk.accounts.formatAccountMetadataId(account.accountId), + _id: accounts.metadata.formatAccountMetadataId(account.accountId), email: account.email, } - metadata = await sdk.accounts.saveMetadata(metadata) + metadata = await accounts.metadata.saveMetadata(metadata) ctx.body = metadata ctx.status = 200 } export const destroy = async (ctx: any) => { - const accountId = sdk.accounts.formatAccountMetadataId(ctx.params.accountId) - await sdk.accounts.destroyMetadata(accountId) + const accountId = accounts.metadata.formatAccountMetadataId( + ctx.params.accountId + ) + await accounts.metadata.destroyMetadata(accountId) ctx.status = 204 } diff --git a/packages/worker/src/api/routes/global/auth.ts b/packages/worker/src/api/routes/global/auth.ts index b13cef2fc6..503182a418 100644 --- a/packages/worker/src/api/routes/global/auth.ts +++ b/packages/worker/src/api/routes/global/auth.ts @@ -33,7 +33,7 @@ router .post( "/api/global/auth/:tenantId/login", buildAuthValidation(), - authController.authenticate + authController.login ) .post("/api/global/auth/logout", authController.logout) .post( @@ -68,21 +68,24 @@ router // GOOGLE - MULTI TENANT .get("/api/global/auth/:tenantId/google", authController.googlePreAuth) - .get("/api/global/auth/:tenantId/google/callback", authController.googleAuth) + .get( + "/api/global/auth/:tenantId/google/callback", + authController.googleCallback + ) // GOOGLE - SINGLE TENANT - DEPRECATED - .get("/api/global/auth/google/callback", authController.googleAuth) - .get("/api/admin/auth/google/callback", authController.googleAuth) + .get("/api/global/auth/google/callback", authController.googleCallback) + .get("/api/admin/auth/google/callback", authController.googleCallback) // OIDC - MULTI TENANT .get( "/api/global/auth/:tenantId/oidc/configs/:configId", authController.oidcPreAuth ) - .get("/api/global/auth/:tenantId/oidc/callback", authController.oidcAuth) + .get("/api/global/auth/:tenantId/oidc/callback", authController.oidcCallback) // OIDC - SINGLE TENANT - DEPRECATED - .get("/api/global/auth/oidc/callback", authController.oidcAuth) - .get("/api/admin/auth/oidc/callback", authController.oidcAuth) + .get("/api/global/auth/oidc/callback", authController.oidcCallback) + .get("/api/admin/auth/oidc/callback", authController.oidcCallback) export default router diff --git a/packages/worker/src/api/routes/global/tests/auth.spec.ts b/packages/worker/src/api/routes/global/tests/auth.spec.ts index ee753d49dc..84f8ce1b0a 100644 --- a/packages/worker/src/api/routes/global/tests/auth.spec.ts +++ b/packages/worker/src/api/routes/global/tests/auth.spec.ts @@ -1,13 +1,27 @@ -jest.mock("nodemailer") -import { TestConfiguration, mocks } from "../../../../tests" -const sendMailMock = mocks.email.mock() -import { events, tenancy } from "@budibase/backend-core" -import { structures } from "@budibase/backend-core/tests" +import { CloudAccount, SSOUser, User } from "@budibase/types" -const expectSetAuthCookie = (res: any) => { - expect( - res.get("Set-Cookie").find((c: string) => c.startsWith("budibase:auth")) - ).toBeDefined() +jest.mock("nodemailer") +import { + TestConfiguration, + mocks, + structures, + generator, +} from "../../../../tests" +const sendMailMock = mocks.email.mock() +import { events, constants } from "@budibase/backend-core" +import { Response } from "superagent" + +import * as userSdk from "../../../../sdk/users" + +function getAuthCookie(response: Response) { + return response.headers["set-cookie"] + .find((s: string) => s.startsWith(`${constants.Cookie.Auth}=`)) + .split("=")[1] + .split(";")[0] +} + +const expectSetAuthCookie = (response: Response) => { + expect(getAuthCookie(response).length > 1).toBe(true) } describe("/api/global/auth", () => { @@ -25,60 +39,247 @@ describe("/api/global/auth", () => { jest.clearAllMocks() }) + async function createSSOUser() { + return config.doInTenant(async () => { + return userSdk.save(structures.users.ssoUser(), { + requirePassword: false, + }) + }) + } + describe("password", () => { describe("POST /api/global/auth/:tenantId/login", () => { - it("should login", () => {}) + it("logs in with correct credentials", async () => { + const tenantId = config.tenantId! + const email = config.user?.email! + const password = config.userPassword + + const response = await config.api.auth.login(tenantId, email, password) + + expectSetAuthCookie(response) + expect(events.auth.login).toBeCalledTimes(1) + }) + + it("should return 403 with incorrect credentials", async () => { + const tenantId = config.tenantId! + const email = config.user?.email! + const password = "incorrect" + + const response = await config.api.auth.login( + tenantId, + email, + password, + { status: 403 } + ) + expect(response.body).toEqual({ + message: "Invalid credentials", + status: 403, + }) + }) + + it("should return 403 when user doesn't exist", async () => { + const tenantId = config.tenantId! + const email = "invaliduser@test.com" + const password = "password" + + const response = await config.api.auth.login( + tenantId, + email, + password, + { status: 403 } + ) + expect(response.body).toEqual({ + message: "Invalid credentials", + status: 403, + }) + }) + + describe("sso user", () => { + let user: User + + async function testSSOUser() { + const tenantId = user.tenantId! + const email = user.email + const password = "test" + + const response = await config.api.auth.login( + tenantId, + email, + password, + { status: 400 } + ) + + expect(response.body).toEqual({ + message: "SSO user cannot login using password", + status: 400, + }) + } + + describe("budibase sso user", () => { + it("should prevent user from logging in", async () => { + user = await createSSOUser() + await testSSOUser() + }) + }) + + describe("root account sso user", () => { + it("should prevent user from logging in", async () => { + user = await config.createUser() + const account = structures.accounts.ssoAccount() as CloudAccount + mocks.accounts.getAccount.mockReturnValueOnce( + Promise.resolve(account) + ) + + await testSSOUser() + }) + }) + }) }) describe("POST /api/global/auth/logout", () => { it("should logout", async () => { - await config.api.auth.logout() + const response = await config.api.auth.logout() expect(events.auth.logout).toBeCalledTimes(1) - // TODO: Verify sessions deleted + const authCookie = getAuthCookie(response) + expect(authCookie).toBe("") }) }) describe("POST /api/global/auth/:tenantId/reset", () => { it("should generate password reset email", async () => { - await tenancy.doInTenant(config.tenant1User!.tenantId, async () => { - const userEmail = structures.email() - const { res, code } = await config.api.auth.requestPasswordReset( + const user = await config.createUser() + + const { res, code } = await config.api.auth.requestPasswordReset( + sendMailMock, + user.email + ) + + expect(res.body).toEqual({ + message: "Please check your email for a reset link.", + }) + expect(sendMailMock).toHaveBeenCalled() + expect(code).toBeDefined() + expect(events.user.passwordResetRequested).toBeCalledTimes(1) + expect(events.user.passwordResetRequested).toBeCalledWith(user) + }) + + describe("sso user", () => { + let user: User + + async function testSSOUser() { + const { res } = await config.api.auth.requestPasswordReset( sendMailMock, - userEmail + user.email, + { status: 400 } ) - const user = await config.getUser(userEmail) expect(res.body).toEqual({ - message: "Please check your email for a reset link.", + message: "SSO user cannot reset password", + status: 400, + error: { + code: "http", + type: "generic", + }, }) - expect(sendMailMock).toHaveBeenCalled() + expect(sendMailMock).not.toHaveBeenCalled() + } - expect(code).toBeDefined() - expect(events.user.passwordResetRequested).toBeCalledTimes(1) - expect(events.user.passwordResetRequested).toBeCalledWith(user) + describe("budibase sso user", () => { + it("should prevent user from generating password reset email", async () => { + user = await createSSOUser() + await testSSOUser() + }) + }) + + describe("root account sso user", () => { + it("should prevent user from generating password reset email", async () => { + user = await config.createUser(structures.users.user()) + const account = structures.accounts.ssoAccount() as CloudAccount + mocks.accounts.getAccount.mockReturnValueOnce( + Promise.resolve(account) + ) + + await testSSOUser() + }) }) }) }) describe("POST /api/global/auth/:tenantId/reset/update", () => { it("should reset password", async () => { - await tenancy.doInTenant(config.tenant1User!.tenantId, async () => { - const userEmail = structures.email() - const { code } = await config.api.auth.requestPasswordReset( - sendMailMock, - userEmail + let user = await config.createUser() + const { code } = await config.api.auth.requestPasswordReset( + sendMailMock, + user.email + ) + delete user.password + + const newPassword = "newpassword" + const res = await config.api.auth.updatePassword(code!, newPassword) + + user = await config.getUser(user.email) + delete user.password + + expect(res.body).toEqual({ message: "password reset successfully." }) + expect(events.user.passwordReset).toBeCalledTimes(1) + expect(events.user.passwordReset).toBeCalledWith(user) + + // login using new password + await config.api.auth.login(user.tenantId, user.email, newPassword) + }) + + describe("sso user", () => { + let user: User | SSOUser + + async function testSSOUser(code: string) { + const res = await config.api.auth.updatePassword( + code!, + generator.string(), + { status: 400 } ) - const user = await config.getUser(userEmail) - delete user.password - const res = await config.api.auth.updatePassword(code) + expect(res.body).toEqual({ + message: "Cannot reset password.", + status: 400, + }) + } - expect(res.body).toEqual({ message: "password reset successfully." }) - expect(events.user.passwordReset).toBeCalledTimes(1) - expect(events.user.passwordReset).toBeCalledWith(user) + describe("budibase sso user", () => { + it("should prevent user from generating password reset email", async () => { + user = await config.createUser() + const { code } = await config.api.auth.requestPasswordReset( + sendMailMock, + user.email + ) + + // convert to sso now that password reset has been requested + const ssoUser = user as SSOUser + ssoUser.providerType = structures.sso.providerType() + delete ssoUser.password + await config.doInTenant(() => userSdk.save(ssoUser)) + + await testSSOUser(code!) + }) + }) + + describe("root account sso user", () => { + it("should prevent user from generating password reset email", async () => { + user = await config.createUser() + const { code } = await config.api.auth.requestPasswordReset( + sendMailMock, + user.email + ) + + // convert to account owner now that password has been requested + const account = structures.accounts.ssoAccount() as CloudAccount + mocks.accounts.getAccount.mockReturnValueOnce( + Promise.resolve(account) + ) + + await testSSOUser(code!) + }) }) - // TODO: Login using new password }) }) }) @@ -153,7 +354,7 @@ describe("/api/global/auth", () => { const location: string = res.get("location") expect( location.startsWith( - "http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2Fdefault%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access" + `http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2F${config.tenantId}%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access` ) ).toBe(true) }) diff --git a/packages/worker/src/api/routes/global/tests/self.spec.ts b/packages/worker/src/api/routes/global/tests/self.spec.ts index d253a7f24e..74d24c7c31 100644 --- a/packages/worker/src/api/routes/global/tests/self.spec.ts +++ b/packages/worker/src/api/routes/global/tests/self.spec.ts @@ -30,7 +30,7 @@ describe("/api/global/self", () => { user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString() expect(res.body._id).toBe(user._id) expect(events.user.updated).toBeCalledTimes(1) - expect(events.user.updated).toBeCalledWith(user) + expect(events.user.updated).toBeCalledWith(dbUser) expect(events.user.passwordUpdated).not.toBeCalled() }) @@ -44,12 +44,11 @@ describe("/api/global/self", () => { const dbUser = await config.getUser(user.email) user._rev = dbUser._rev user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString() - delete user.password expect(res.body._id).toBe(user._id) expect(events.user.updated).toBeCalledTimes(1) - expect(events.user.updated).toBeCalledWith(user) + expect(events.user.updated).toBeCalledWith(dbUser) expect(events.user.passwordUpdated).toBeCalledTimes(1) - expect(events.user.passwordUpdated).toBeCalledWith(user) + expect(events.user.passwordUpdated).toBeCalledWith(dbUser) }) }) }) diff --git a/packages/worker/src/api/routes/system/tests/accounts.spec.ts b/packages/worker/src/api/routes/system/tests/accounts.spec.ts index fd54dd2b0a..7df2950212 100644 --- a/packages/worker/src/api/routes/system/tests/accounts.spec.ts +++ b/packages/worker/src/api/routes/system/tests/accounts.spec.ts @@ -1,4 +1,4 @@ -import sdk from "../../../../sdk" +import * as accounts from "../../../../sdk/accounts" import { TestConfiguration, structures } from "../../../../tests" import { v4 as uuid } from "uuid" @@ -24,8 +24,8 @@ describe("accounts", () => { const response = await config.api.accounts.saveMetadata(account) - const id = sdk.accounts.formatAccountMetadataId(account.accountId) - const metadata = await sdk.accounts.getMetadata(id) + const id = accounts.metadata.formatAccountMetadataId(account.accountId) + const metadata = await accounts.metadata.getMetadata(id) expect(response).toStrictEqual(metadata) }) }) @@ -37,7 +37,7 @@ describe("accounts", () => { await config.api.accounts.destroyMetadata(account.accountId) - const deleted = await sdk.accounts.getMetadata(account.accountId) + const deleted = await accounts.metadata.getMetadata(account.accountId) expect(deleted).toBe(undefined) }) diff --git a/packages/worker/src/environment.ts b/packages/worker/src/environment.ts index 52fec210bc..71fd89f276 100644 --- a/packages/worker/src/environment.ts +++ b/packages/worker/src/environment.ts @@ -26,6 +26,8 @@ function parseIntSafe(number: any) { } } +const selfHosted = !!parseInt(process.env.SELF_HOSTED || "") + const environment = { // auth MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, @@ -49,7 +51,7 @@ const environment = { CLUSTER_PORT: process.env.CLUSTER_PORT, // flags NODE_ENV: process.env.NODE_ENV, - SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED || ""), + SELF_HOSTED: selfHosted, LOG_LEVEL: process.env.LOG_LEVEL, MULTI_TENANCY: process.env.MULTI_TENANCY, DISABLE_ACCOUNT_PORTAL: process.env.DISABLE_ACCOUNT_PORTAL, @@ -65,6 +67,18 @@ const environment = { CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600, SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD, ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY, + /** + * Mock the email service in use - links to ethereal hosted emails are logged instead. + */ + ENABLE_EMAIL_TEST_MODE: process.env.ENABLE_EMAIL_TEST_MODE, + /** + * Enable to allow an admin user to login using a password. + * This can be useful to prevent lockout when configuring SSO. + * However, this should be turned OFF by default for security purposes. + */ + ENABLE_SSO_MAINTENANCE_MODE: selfHosted + ? process.env.ENABLE_SSO_MAINTENANCE_MODE + : false, _set(key: any, value: any) { process.env[key] = value // @ts-ignore diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 1eff6c06fb..1e3ff3cbdf 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -25,6 +25,12 @@ const koaSession = require("koa-session") const logger = require("koa-pino-logger") import destroyable from "server-destroy" +if (env.ENABLE_SSO_MAINTENANCE_MODE) { + console.warn( + "Warning: ENABLE_SSO_MAINTENANCE_MODE is set. It is recommended this flag is disabled if maintenance is not in progress" + ) +} + // this will setup http and https proxies form env variables bootstrap() diff --git a/packages/worker/src/sdk/accounts/index.ts b/packages/worker/src/sdk/accounts/index.ts index f2ae03040e..72db8c3d85 100644 --- a/packages/worker/src/sdk/accounts/index.ts +++ b/packages/worker/src/sdk/accounts/index.ts @@ -1 +1,2 @@ -export * from "./accounts" +export * as metadata from "./metadata" +export { accounts as api } from "@budibase/backend-core" diff --git a/packages/worker/src/sdk/accounts/accounts.ts b/packages/worker/src/sdk/accounts/metadata.ts similarity index 99% rename from packages/worker/src/sdk/accounts/accounts.ts rename to packages/worker/src/sdk/accounts/metadata.ts index e43285087b..64065e8b78 100644 --- a/packages/worker/src/sdk/accounts/accounts.ts +++ b/packages/worker/src/sdk/accounts/metadata.ts @@ -2,7 +2,6 @@ import { AccountMetadata } from "@budibase/types" import { db, StaticDatabases, - HTTPError, DocumentType, SEPARATOR, } from "@budibase/backend-core" diff --git a/packages/worker/src/sdk/auth/auth.ts b/packages/worker/src/sdk/auth/auth.ts new file mode 100644 index 0000000000..15a4f3c7e7 --- /dev/null +++ b/packages/worker/src/sdk/auth/auth.ts @@ -0,0 +1,86 @@ +import { + auth as authCore, + tenancy, + utils as coreUtils, + sessions, + events, + HTTPError, +} from "@budibase/backend-core" +import { PlatformLogoutOpts, User } from "@budibase/types" +import jwt from "jsonwebtoken" +import env from "../../environment" +import * as userSdk from "../users" +import * as emails from "../../utilities/email" +import * as redis from "../../utilities/redis" +import { EmailTemplatePurpose } from "../../constants" + +// LOGIN / LOGOUT + +export async function loginUser(user: User) { + const sessionId = coreUtils.newid() + const tenantId = tenancy.getTenantId() + await sessions.createASession(user._id!, { sessionId, tenantId }) + const token = jwt.sign( + { + userId: user._id, + sessionId, + tenantId, + }, + env.JWT_SECRET! + ) + return token +} + +export async function logout(opts: PlatformLogoutOpts) { + // TODO: This should be moved out of core and into worker only + // account-portal can call worker endpoint + return authCore.platformLogout(opts) +} + +// PASSWORD MANAGEMENT + +/** + * Reset the user password, used as part of a forgotten password flow. + */ +export const reset = async (email: string) => { + const configured = await emails.isEmailConfigured() + if (!configured) { + throw new HTTPError( + "Please contact your platform administrator, SMTP is not configured.", + 400 + ) + } + + const user = await userSdk.core.getGlobalUserByEmail(email) + // exit if user doesn't exist + if (!user) { + return + } + + // exit if user has sso + if (await userSdk.isPreventSSOPasswords(user)) { + throw new HTTPError("SSO user cannot reset password", 400) + } + + // send password reset + await emails.sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, { + user, + subject: "{{ company }} platform password reset", + }) + await events.user.passwordResetRequested(user) +} + +/** + * Perform the user password update if the provided reset code is valid. + */ +export const resetUpdate = async (resetCode: string, password: string) => { + const { userId } = await redis.checkResetPasswordCode(resetCode) + + let user = await userSdk.getUser(userId) + user.password = password + user = await userSdk.save(user) + + // remove password from the user before sending events + delete user.password + await events.user.passwordReset(user) +} diff --git a/packages/worker/src/sdk/auth/index.ts b/packages/worker/src/sdk/auth/index.ts new file mode 100644 index 0000000000..306751af96 --- /dev/null +++ b/packages/worker/src/sdk/auth/index.ts @@ -0,0 +1 @@ +export * from "./auth" diff --git a/packages/worker/src/sdk/users/events.ts b/packages/worker/src/sdk/users/events.ts index 17c4748dff..7d86182a3c 100644 --- a/packages/worker/src/sdk/users/events.ts +++ b/packages/worker/src/sdk/users/events.ts @@ -84,6 +84,10 @@ export const handleSaveEvents = async ( ) { await events.user.passwordForceReset(user) } + + if (user.password !== existingUser.password) { + await events.user.passwordUpdated(user) + } } else { await events.user.created(user) } diff --git a/packages/worker/src/sdk/users/index.ts b/packages/worker/src/sdk/users/index.ts index 056d6e5675..2eaa0e68a2 100644 --- a/packages/worker/src/sdk/users/index.ts +++ b/packages/worker/src/sdk/users/index.ts @@ -1 +1,2 @@ export * from "./users" +export { users as core } from "@budibase/backend-core" diff --git a/packages/worker/src/sdk/users/tests/users.spec.ts b/packages/worker/src/sdk/users/tests/users.spec.ts new file mode 100644 index 0000000000..41d9298997 --- /dev/null +++ b/packages/worker/src/sdk/users/tests/users.spec.ts @@ -0,0 +1,52 @@ +import { structures } from "../../../tests" +import * as users from "../users" +import env from "../../../environment" +import { mocks } from "@budibase/backend-core/tests" +import { CloudAccount } from "@budibase/types" + +describe("users", () => { + describe("isPreventSSOPasswords", () => { + it("returns true for sso account user", async () => { + const user = structures.users.user() + mocks.accounts.getAccount.mockReturnValue( + Promise.resolve(structures.accounts.ssoAccount() as CloudAccount) + ) + const result = await users.isPreventSSOPasswords(user) + expect(result).toBe(true) + }) + + it("returns true for sso user", async () => { + const user = structures.users.ssoUser() + const result = await users.isPreventSSOPasswords(user) + expect(result).toBe(true) + }) + + describe("sso maintenance mode", () => { + beforeEach(() => { + env._set("ENABLE_SSO_MAINTENANCE_MODE", true) + }) + + afterEach(() => { + env._set("ENABLE_SSO_MAINTENANCE_MODE", false) + }) + + describe("non-admin user", () => { + it("returns true", async () => { + const user = structures.users.ssoUser() + const result = await users.isPreventSSOPasswords(user) + expect(result).toBe(true) + }) + }) + + describe("admin user", () => { + it("returns false", async () => { + const user = structures.users.ssoUser({ + user: structures.users.adminUser(), + }) + const result = await users.isPreventSSOPasswords(user) + expect(result).toBe(false) + }) + }) + }) + }) +}) diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 1d05f6d84f..7d4a2f04f0 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -6,12 +6,11 @@ import { cache, constants, db as dbUtils, - deprovisioning, events, HTTPError, - migrations, sessions, tenancy, + platform, users as usersCore, utils, ViewName, @@ -21,21 +20,22 @@ import { AllDocsResponse, BulkUserResponse, CloudAccount, - CreateUserResponse, InviteUsersRequest, InviteUsersResponse, - MigrationType, + isSSOAccount, + isSSOUser, PlatformUser, PlatformUserByEmail, RowResponse, SearchUsersRequest, + UpdateSelf, User, - ThirdPartyUser, - isUser, + SaveUserOpts, } from "@budibase/types" import { sendEmail } from "../../utilities/email" import { EmailTemplatePurpose } from "../../constants" import { groups as groupsSdk } from "@budibase/pro" +import * as accountSdk from "../accounts" const PAGE_LIMIT = 8 @@ -94,26 +94,23 @@ export const paginatedUsers = async ({ }) } +export async function getUserByEmail(email: string) { + return usersCore.getGlobalUserByEmail(email) +} + /** * Gets a user by ID from the global database, based on the current tenancy. */ export const getUser = async (userId: string) => { - const db = tenancy.getGlobalDB() - let user = await db.get(userId) + const user = await usersCore.getById(userId) if (user) { delete user.password } return user } -export interface SaveUserOpts { - hashPassword?: boolean - requirePassword?: boolean - currentUserId?: string -} - const buildUser = async ( - user: User | ThirdPartyUser, + user: User, opts: SaveUserOpts = { hashPassword: true, requirePassword: true, @@ -121,11 +118,13 @@ const buildUser = async ( tenantId: string, dbUser?: any ): Promise => { - let fullUser = user as User - let { password, _id } = fullUser + let { password, _id } = user let hashedPassword if (password) { + if (await isPreventSSOPasswords(user)) { + throw new HTTPError("SSO user cannot set password", 400) + } hashedPassword = opts.hashPassword ? await utils.hash(password) : password } else if (dbUser) { hashedPassword = dbUser.password @@ -135,10 +134,10 @@ const buildUser = async ( _id = _id || dbUtils.generateGlobalUserID() - fullUser = { + const fullUser = { createdAt: Date.now(), ...dbUser, - ...fullUser, + ...user, _id, password: hashedPassword, tenantId, @@ -189,10 +188,36 @@ const validateUniqueUser = async (email: string, tenantId: string) => { } } +export async function isPreventSSOPasswords(user: User) { + // when in maintenance mode we allow sso users with the admin role + // to perform any password action - this prevents lockout + if (env.ENABLE_SSO_MAINTENANCE_MODE && user.admin?.global) { + return false + } + + // Check local sso + if (isSSOUser(user)) { + return true + } + + // Check account sso + const account = await accountSdk.api.getAccount(user.email) + return !!(account && isSSOAccount(account)) +} + +export async function updateSelf(id: string, data: UpdateSelf) { + let user = await getUser(id) + user = { + ...user, + ...data, + } + return save(user) +} + export const save = async ( - user: User | ThirdPartyUser, + user: User, opts: SaveUserOpts = {} -): Promise => { +): Promise => { // default booleans to true if (opts.hashPassword == null) { opts.hashPassword = true @@ -264,7 +289,7 @@ export const save = async ( builtUser._rev = response.rev await eventHelpers.handleSaveEvents(builtUser, dbUser) - await addTenant(tenantId, _id, email) + await platform.users.addUser(tenantId, builtUser._id!, builtUser.email) await cache.user.invalidateUser(response.id) // let server know to sync user @@ -272,11 +297,8 @@ export const save = async ( await Promise.all(groupPromises) - return { - _id: response.id, - _rev: response.rev, - email, - } + // finally returned the saved user from the db + return db.get(builtUser._id!) } catch (err: any) { if (err.status === 409) { throw "User exists already" @@ -286,21 +308,6 @@ export const save = async ( } } -export const addTenant = async ( - tenantId: string, - _id: string, - email: string -) => { - if (env.MULTI_TENANCY) { - const afterCreateTenant = () => - migrations.backPopulateMigrations({ - type: MigrationType.GLOBAL, - tenantId, - }) - await tenancy.tryAddTenant(tenantId, _id, email, afterCreateTenant) - } -} - const getExistingTenantUsers = async (emails: string[]): Promise => { const lcEmails = emails.map(email => email.toLowerCase()) const params = { @@ -432,7 +439,7 @@ export const bulkCreate = async ( for (const user of usersToBulkSave) { // TODO: Refactor to bulk insert users into the info db // instead of relying on looping tenant creation - await addTenant(tenantId, user._id, user.email) + await platform.users.addUser(tenantId, user._id, user.email) await eventHelpers.handleSaveEvents(user, undefined) await apps.syncUserInApps(user._id) } @@ -566,7 +573,7 @@ export const destroy = async (id: string, currentUser: any) => { } } - await deprovisioning.removeUserFromInfoDB(dbUser) + await platform.users.removeUser(dbUser) await db.remove(userId, dbUser._rev) @@ -579,7 +586,7 @@ export const destroy = async (id: string, currentUser: any) => { const bulkDeleteProcessing = async (dbUser: User) => { const userId = dbUser._id as string - await deprovisioning.removeUserFromInfoDB(dbUser) + await platform.users.removeUser(dbUser) await eventHelpers.handleDeleteEvents(dbUser) await cache.user.invalidateUser(userId) await sessions.invalidateSessions(userId, { reason: "bulk-deletion" }) diff --git a/packages/worker/src/tests/TestConfiguration.ts b/packages/worker/src/tests/TestConfiguration.ts index 7d075e7fef..3004d0aed4 100644 --- a/packages/worker/src/tests/TestConfiguration.ts +++ b/packages/worker/src/tests/TestConfiguration.ts @@ -22,7 +22,7 @@ import { env as coreEnv, } from "@budibase/backend-core" import structures, { CSRF_TOKEN } from "./structures" -import { CreateUserResponse, User, AuthToken } from "@budibase/types" +import { SaveUserResponse, User, AuthToken } from "@budibase/types" import API from "./api" class TestConfiguration { @@ -226,7 +226,7 @@ class TestConfiguration { user = structures.users.user() } const response = await this._req(user, null, controllers.users.save) - const body = response as CreateUserResponse + const body = response as SaveUserResponse return this.getUser(body.email) } diff --git a/packages/worker/src/tests/api/auth.ts b/packages/worker/src/tests/api/auth.ts index ccbf747273..bd0471ca74 100644 --- a/packages/worker/src/tests/api/auth.ts +++ b/packages/worker/src/tests/api/auth.ts @@ -1,21 +1,39 @@ -import structures from "../structures" import TestConfiguration from "../TestConfiguration" -import { TestAPI } from "./base" +import { TestAPI, TestAPIOpts } from "./base" export class AuthAPI extends TestAPI { constructor(config: TestConfiguration) { super(config) } - updatePassword = (code: string) => { + updatePassword = ( + resetCode: string, + password: string, + opts?: TestAPIOpts + ) => { return this.request .post(`/api/global/auth/${this.config.getTenantId()}/reset/update`) .send({ - password: "newpassword", - resetCode: code, + password, + resetCode, }) .expect("Content-Type", /json/) - .expect(200) + .expect(opts?.status ? opts.status : 200) + } + + login = ( + tenantId: string, + email: string, + password: string, + opts?: TestAPIOpts + ) => { + return this.request + .post(`/api/global/auth/${tenantId}/login`) + .send({ + username: email, + password: password, + }) + .expect(opts?.status ? opts.status : 200) } logout = () => { @@ -25,25 +43,31 @@ export class AuthAPI extends TestAPI { .expect(200) } - requestPasswordReset = async (sendMailMock: any, userEmail: string) => { + requestPasswordReset = async ( + sendMailMock: any, + email: string, + opts?: TestAPIOpts + ) => { await this.config.saveSmtpConfig() await this.config.saveSettingsConfig() - await this.config.createUser({ - ...structures.users.user(), - email: userEmail, - }) + const res = await this.request .post(`/api/global/auth/${this.config.getTenantId()}/reset`) .send({ - email: userEmail, + email: email, }) .expect("Content-Type", /json/) - .expect(200) - const emailCall = sendMailMock.mock.calls[0][0] - const parts = emailCall.html.split( - `http://localhost:10000/builder/auth/reset?code=` - ) - const code = parts[1].split('"')[0].split("&")[0] + .expect(opts?.status ? opts.status : 200) + + let code: string | undefined + if (res.status === 200) { + const emailCall = sendMailMock.mock.calls[0][0] + const parts = emailCall.html.split( + `http://localhost:10000/builder/auth/reset?code=` + ) + code = parts[1].split('"')[0].split("&")[0] + } + return { code, res } } } diff --git a/packages/worker/src/tests/structures/index.ts b/packages/worker/src/tests/structures/index.ts index dad055f7a7..bec15df6dd 100644 --- a/packages/worker/src/tests/structures/index.ts +++ b/packages/worker/src/tests/structures/index.ts @@ -1,6 +1,5 @@ import { structures } from "@budibase/backend-core/tests" import * as configs from "./configs" -import * as users from "./users" import * as groups from "./groups" import { v4 as uuid } from "uuid" @@ -11,7 +10,6 @@ const pkg = { ...structures, uuid, configs, - users, TENANT_ID, CSRF_TOKEN, groups, diff --git a/packages/worker/src/tests/structures/users.ts b/packages/worker/src/tests/structures/users.ts deleted file mode 100644 index 3348670b7d..0000000000 --- a/packages/worker/src/tests/structures/users.ts +++ /dev/null @@ -1,37 +0,0 @@ -export const email = "test@test.com" -import { AdminUser, BuilderUser, User } from "@budibase/types" -import { v4 as uuid } from "uuid" - -export const newEmail = () => { - return `${uuid()}@test.com` -} - -export const user = (userProps?: any): User => { - return { - email: newEmail(), - password: "test", - roles: { app_test: "admin" }, - ...userProps, - } -} - -export const adminUser = (userProps?: any): AdminUser => { - return { - ...user(userProps), - admin: { - global: true, - }, - builder: { - global: true, - }, - } -} - -export const builderUser = (userProps?: any): BuilderUser => { - return { - ...user(userProps), - builder: { - global: true, - }, - } -} diff --git a/packages/worker/src/utilities/email.ts b/packages/worker/src/utilities/email.ts index 7ec3447707..66e860edcb 100644 --- a/packages/worker/src/utilities/email.ts +++ b/packages/worker/src/utilities/email.ts @@ -26,7 +26,7 @@ type SendEmailOpts = { automation?: boolean } -const TEST_MODE = false +const TEST_MODE = env.ENABLE_EMAIL_TEST_MODE && env.isDev() const TYPE = TemplateType.EMAIL const FULL_EMAIL_PURPOSES = [ @@ -62,8 +62,8 @@ function createSMTPTransport(config: any) { host: "smtp.ethereal.email", secure: false, auth: { - user: "don.bahringer@ethereal.email", - pass: "yCKSH8rWyUPbnhGYk9", + user: "wyatt.zulauf29@ethereal.email", + pass: "tEwDtHBWWxusVWAPfa", }, } } From bd16f3a55dfe802cc11bc2c7ecac8434494cb0fc Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 21 Feb 2023 09:03:29 +0000 Subject: [PATCH 053/273] Re-add maxWorkers=2 to worker tests --- packages/worker/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/worker/package.json b/packages/worker/package.json index 1ae0327441..0248199341 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -22,7 +22,7 @@ "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", "dev:builder": "npm run dev:stack:init && nodemon", - "test": "jest --coverage", + "test": "jest --coverage --maxWorkers=2", "test:watch": "jest --watch", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", From 3c5d5f4c25ea45663edb2c26afc8ebf1bc6879c9 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 09:42:56 +0000 Subject: [PATCH 054/273] Fix relation get test to test expected behaviour --- packages/server/src/integration-test/postgres.spec.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index ecfb532e7f..32d4204ea1 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -419,14 +419,16 @@ describe("row api - postgres", () => { describe("given a row with relation data", () => { let row: Row + let foreignRow: Row beforeEach(async () => { let [createdRow] = await populatePrimaryRows(1, { createForeignRow: true, }) row = createdRow.row + foreignRow = createdRow.foreignRow! }) - it("foreign key fields are not retrieved", async () => { + it("only foreign keys are retrieved", async () => { const res = await getRow(primaryPostgresTable._id, row.id) expect(res.status).toBe(200) @@ -436,7 +438,12 @@ describe("row api - postgres", () => { _id: expect.any(String), _rev: expect.any(String), }) - expect(res.body.foreignField).toBeUndefined() + expect( + res.body[`fk_${auxPostgresTable.name}_foreignField`] + ).toBeDefined() + expect(res.body[`fk_${auxPostgresTable.name}_foreignField`]).toBe( + foreignRow.id + ) }) }) }) From 483f15a5d6a08337d52c149d566c00fc4c1ef451 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 09:51:07 +0000 Subject: [PATCH 055/273] Add explicit check for the foreign field --- packages/server/src/integration-test/postgres.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 32d4204ea1..c688600e8d 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -438,6 +438,9 @@ describe("row api - postgres", () => { _id: expect.any(String), _rev: expect.any(String), }) + + expect(res.body.foreignField).toBeUndefined() + expect( res.body[`fk_${auxPostgresTable.name}_foreignField`] ).toBeDefined() From dc691bcaf7881c41c68bd33d218c7f45d8b117a1 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 21 Feb 2023 10:48:55 +0000 Subject: [PATCH 056/273] integrate properly with audit log search api --- packages/bbui/src/Form/Core/Picker.svelte | 4 +- .../_components/AppColumnRenderer.svelte | 5 ++ .../auditLogs/_components/TimeRenderer.svelte | 7 +- .../auditLogs/_components/UserRenderer.svelte | 10 ++- .../portal/account/auditLogs/index.svelte | 75 ++++++++++++------- .../builder/src/stores/portal/auditLogs.js | 20 +++-- 6 files changed, 80 insertions(+), 41 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index fb0ce00824..ace41aa35b 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -145,7 +145,8 @@ {#if autocomplete} (fetchTerm = event.detail)} + on:change={event => + fetchTerm ? (fetchTerm = event.detail) : (searchTerm = event.detail)} {disabled} placeholder="Search" /> @@ -265,7 +266,6 @@ .popover-content :global(.spectrum-Search) { margin-top: -1px; margin-left: -1px; - width: calc(100% + 2px); } .popover-content :global(.spectrum-Search input) { height: auto; diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte new file mode 100644 index 0000000000..f6665dff28 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte @@ -0,0 +1,5 @@ + + +
{value.name}
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte index 7ec044604e..b6c0262b47 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/TimeRenderer.svelte @@ -1,12 +1,11 @@
- {dayjs(row.date).fromNow()} + {dayjs(row.timestamp).fromNow()}
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte index c9a69b4316..07551da3bc 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -1,6 +1,14 @@ - + diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 88f042d240..09b8466d8e 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -13,17 +13,17 @@ import { licensing, users, apps, auditLogs } from "stores/portal" import LockedFeature from "../../_components/LockedFeature.svelte" import { createPaginationStore } from "helpers/pagination" - import { setContext } from "svelte" + import { onMount, setContext } from "svelte" import ViewDetailsRenderer from "./_components/ViewDetailsRenderer.svelte" import UserRenderer from "./_components/UserRenderer.svelte" import TimeRenderer from "./_components/TimeRenderer.svelte" + import AppColumnRenderer from "./_components/AppColumnRenderer.svelte" const schema = { - name: { width: "1fr" }, - date: { width: "1.5fr" }, + date: { width: "0.8fr" }, user: { width: "0.5fr" }, - app: { width: "1fr" }, - event: { width: "1fr" }, + app: { width: "1fr", fieldName: "name" }, + name: { width: "1fr" }, view: { width: "auto", borderLeft: true, displayName: "" }, } @@ -40,6 +40,10 @@ column: "date", component: TimeRenderer, }, + { + column: "app", + component: AppColumnRenderer, + }, ] let userSearchTerm = "" @@ -55,22 +59,15 @@ let sidePanelVisible = false let startDate, endDate - let data = [ - { - name: "User created", - date: "2023-02-14T10:19:52.021Z", - user: "Peter Clement", - app: "School Admin Panel", - event: "User added", - metadata: { - name: "Peter Clement", - email: "", - }, - }, - ] - $: fetchUsers(userPage, userSearchTerm) - $: fetchLogs(logsPage, logSearchTerm) + $: fetchLogs( + logsPage, + logSearchTerm, + startDate, + endDate, + selectedUsers, + selectedApps + ) $: userPage = $userPageInfo.page $: logsPage = $logsPageInfo.page @@ -97,7 +94,14 @@ } } - const fetchLogs = async (logsPage, search) => { + const fetchLogs = async ( + logsPage, + search, + startDate, + endDate, + selectedUsers, + selectedApps + ) => { if ($logsPageInfo.loading) { return } @@ -117,7 +121,10 @@ userIds: selectedUsers, appIds: selectedApps, }) - logsPageInfo.fetched($auditLogs.hasNextPage, $auditLogs.nextPage) + logsPageInfo.fetched( + $auditLogs.logs.hasNextPage, + $auditLogs.logs.nextPage + ) } catch (error) { console.log(error) notifications.error("Error getting audit logs") @@ -170,6 +177,10 @@ setContext("auditLogs", { viewDetails, }) + + onMount(async () => { + await auditLogs.getEventDefinitions() + })
app.appId} + getOptionValue={app => "app_dev_" + app.appId} getOptionLabel={app => app.name} options={$apps} bind:value={selectedApps} />
- + event[0]} + getOptionLabel={event => event[1]} + options={Object.entries($auditLogs.events)} + placeholder="All events" + label="Event" + />
@@ -228,14 +247,14 @@
- +
Audit Logs { sidePanelVisible = false }} @@ -263,7 +283,6 @@
{ + return { ...state, logs: { ...paged, opts } } }) + return paged } } async function getEventDefinitions() { - return await API.getEventDefinitions() + const events = await API.getEventDefinitions() + + update(state => { + return { ...state, ...events } + }) + + console.log(events) } async function downloadLogs(opts = {}) { From 0c838196e4751ffea9ace440ebb8d357f69393e8 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 21 Feb 2023 10:52:11 +0000 Subject: [PATCH 057/273] Enable mock redis for integration tests --- packages/builder/setup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/builder/setup.js b/packages/builder/setup.js index 744c20896a..b3fd96877b 100644 --- a/packages/builder/setup.js +++ b/packages/builder/setup.js @@ -19,6 +19,7 @@ process.env.COUCH_DB_USER = "budibase" process.env.COUCH_DB_PASSWORD = "budibase" process.env.INTERNAL_API_KEY = "budibase" process.env.ALLOW_DEV_AUTOMATIONS = 1 +process.env.MOCK_REDIS = 1 // Stop info logs polluting test outputs process.env.LOG_LEVEL = "error" From e6d7c22efa0a82c65020ef37602131508bf51b83 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 11:22:46 +0000 Subject: [PATCH 058/273] v2.3.17-alpha.5 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index dda0b8dfc8..63e9ac45f9 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 75c16447ba..ceafebcbc5 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.4", + "@budibase/types": "2.3.17-alpha.5", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index bf2782d843..da9fdbca60 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "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.3.17-alpha.4", + "@budibase/string-templates": "2.3.17-alpha.5", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 049b8d2a9f..00fe30b057 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.4", - "@budibase/client": "2.3.17-alpha.4", - "@budibase/frontend-core": "2.3.17-alpha.4", - "@budibase/string-templates": "2.3.17-alpha.4", + "@budibase/bbui": "2.3.17-alpha.5", + "@budibase/client": "2.3.17-alpha.5", + "@budibase/frontend-core": "2.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.5", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 1d92be8c84..036120eac5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "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.3.17-alpha.4", - "@budibase/string-templates": "2.3.17-alpha.4", - "@budibase/types": "2.3.17-alpha.4", + "@budibase/backend-core": "2.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.5", + "@budibase/types": "2.3.17-alpha.5", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index b40f27f287..97ebc2b2e0 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "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.3.17-alpha.4", - "@budibase/frontend-core": "2.3.17-alpha.4", - "@budibase/string-templates": "2.3.17-alpha.4", + "@budibase/bbui": "2.3.17-alpha.5", + "@budibase/frontend-core": "2.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.5", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index c4222bd0e3..7a42ba09db 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.4", + "@budibase/bbui": "2.3.17-alpha.5", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index bd6fa2a9d4..36328c51d8 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 0388465ce4..3888c55f46 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "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.3.17-alpha.4", - "@budibase/client": "2.3.17-alpha.4", + "@budibase/backend-core": "2.3.17-alpha.5", + "@budibase/client": "2.3.17-alpha.5", "@budibase/pro": "2.3.17-alpha.4", - "@budibase/string-templates": "2.3.17-alpha.4", - "@budibase/types": "2.3.17-alpha.4", + "@budibase/string-templates": "2.3.17-alpha.5", + "@budibase/types": "2.3.17-alpha.5", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index fad3b4d59f..d5eb7e3f04 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index a5441b58a2..0b1ee30b2e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 0248199341..b6bc942add 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.4", + "version": "2.3.17-alpha.5", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.4", + "@budibase/backend-core": "2.3.17-alpha.5", "@budibase/pro": "2.3.17-alpha.4", - "@budibase/string-templates": "2.3.17-alpha.4", - "@budibase/types": "2.3.17-alpha.4", + "@budibase/string-templates": "2.3.17-alpha.5", + "@budibase/types": "2.3.17-alpha.5", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From cbddc7ee4f537e78f01450eeb4c62b82e2882c9f Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 11:26:45 +0000 Subject: [PATCH 059/273] Update pro version to 2.3.17-alpha.5 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 3888c55f46..c647378d54 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.5", "@budibase/client": "2.3.17-alpha.5", - "@budibase/pro": "2.3.17-alpha.4", + "@budibase/pro": "2.3.17-alpha.5", "@budibase/string-templates": "2.3.17-alpha.5", "@budibase/types": "2.3.17-alpha.5", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 3fa6a84ad9..2d6ad91005 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.4.tgz#efe13cc2eb9a02223cff46228af8370a5a91db11" - integrity sha512-h9aCz+5uAQOvQiimULShKkXdQgyiwvgcxq3wqEvNHsAxmlslaJJouStWhvxBdsFiOW9K2CyI/8PeUBBRlAU0AQ== +"@budibase/backend-core@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.5.tgz#5bd380c9bf3835694729f1c68c44a77aec7b66dd" + integrity sha512-Nv/BsmItQcdi30oHvNEeRRkDxooMR3shZksb14NDWfdP9gxjVOkUltA2HELujL2ZEg4mismau/0oy9kZy5z3Og== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.4" + "@budibase/types" "2.3.17-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.4.tgz#56e945bd960eca8c8b2a04a3dd606df392bf5792" - integrity sha512-DJtKCc5/XXAnrvI5sS+joVuDYOLgwFmDYwLbssJgSQzGXNqepN/ikGq6eFCKn/99fRYBGREfwXwAlxXveZxPWA== +"@budibase/pro@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.5.tgz#4007ab38a5a88cedc1c0ba48543fcbfdf0c58a2a" + integrity sha512-pR7i7ehpoJ08Pq4Xs5vFJcZLvLkfCDS3AvJV1e0j9IDPD73kqiqCxgOF9rE27NTLf0BvbPK5Vj4Z7RPCxIJv7g== dependencies: - "@budibase/backend-core" "2.3.17-alpha.4" - "@budibase/types" "2.3.17-alpha.4" + "@budibase/backend-core" "2.3.17-alpha.5" + "@budibase/types" "2.3.17-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.4.tgz#63eb756160da7ace5459e303874f5e67425c6988" - integrity sha512-us/gGZPHimHsYNAnJ5yGdxeThT065wofJ2sfg0aD81P8nq3F2mevBoUmci/KRYdrQ9EsgpZ3Ou6CqnhnV8WmfA== +"@budibase/types@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.5.tgz#a8c31f49ac9f8b312317fd6fe547ea76d89d059b" + integrity sha512-qp51pVnOaUf42plQjPlCXZVMTIFKrkkhiJ+XaClnekRmyAYaz7JUIex+QTDbmUF4i0WbZRc0MgUCVQxlKkWotA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index b6bc942add..c1a1a8a001 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.5", - "@budibase/pro": "2.3.17-alpha.4", + "@budibase/pro": "2.3.17-alpha.5", "@budibase/string-templates": "2.3.17-alpha.5", "@budibase/types": "2.3.17-alpha.5", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 3c12fd53b6..5c534eefe1 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.4.tgz#efe13cc2eb9a02223cff46228af8370a5a91db11" - integrity sha512-h9aCz+5uAQOvQiimULShKkXdQgyiwvgcxq3wqEvNHsAxmlslaJJouStWhvxBdsFiOW9K2CyI/8PeUBBRlAU0AQ== +"@budibase/backend-core@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.5.tgz#5bd380c9bf3835694729f1c68c44a77aec7b66dd" + integrity sha512-Nv/BsmItQcdi30oHvNEeRRkDxooMR3shZksb14NDWfdP9gxjVOkUltA2HELujL2ZEg4mismau/0oy9kZy5z3Og== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.4" + "@budibase/types" "2.3.17-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.4.tgz#56e945bd960eca8c8b2a04a3dd606df392bf5792" - integrity sha512-DJtKCc5/XXAnrvI5sS+joVuDYOLgwFmDYwLbssJgSQzGXNqepN/ikGq6eFCKn/99fRYBGREfwXwAlxXveZxPWA== +"@budibase/pro@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.5.tgz#4007ab38a5a88cedc1c0ba48543fcbfdf0c58a2a" + integrity sha512-pR7i7ehpoJ08Pq4Xs5vFJcZLvLkfCDS3AvJV1e0j9IDPD73kqiqCxgOF9rE27NTLf0BvbPK5Vj4Z7RPCxIJv7g== dependencies: - "@budibase/backend-core" "2.3.17-alpha.4" - "@budibase/types" "2.3.17-alpha.4" + "@budibase/backend-core" "2.3.17-alpha.5" + "@budibase/types" "2.3.17-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.4": - version "2.3.17-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.4.tgz#63eb756160da7ace5459e303874f5e67425c6988" - integrity sha512-us/gGZPHimHsYNAnJ5yGdxeThT065wofJ2sfg0aD81P8nq3F2mevBoUmci/KRYdrQ9EsgpZ3Ou6CqnhnV8WmfA== +"@budibase/types@2.3.17-alpha.5": + version "2.3.17-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.5.tgz#a8c31f49ac9f8b312317fd6fe547ea76d89d059b" + integrity sha512-qp51pVnOaUf42plQjPlCXZVMTIFKrkkhiJ+XaClnekRmyAYaz7JUIex+QTDbmUF4i0WbZRc0MgUCVQxlKkWotA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 9ed759580f436e598070dc44fbdd3b520491e4f3 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 11:52:45 +0000 Subject: [PATCH 060/273] v2.3.17-alpha.6 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 63e9ac45f9..80460af875 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index ceafebcbc5..68323e05ac 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.5", + "@budibase/types": "2.3.17-alpha.6", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index da9fdbca60..ccaadf77b1 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "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.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.6", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 00fe30b057..761f17dd6d 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.5", - "@budibase/client": "2.3.17-alpha.5", - "@budibase/frontend-core": "2.3.17-alpha.5", - "@budibase/string-templates": "2.3.17-alpha.5", + "@budibase/bbui": "2.3.17-alpha.6", + "@budibase/client": "2.3.17-alpha.6", + "@budibase/frontend-core": "2.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.6", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 036120eac5..a4c21bef29 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "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.3.17-alpha.5", - "@budibase/string-templates": "2.3.17-alpha.5", - "@budibase/types": "2.3.17-alpha.5", + "@budibase/backend-core": "2.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.6", + "@budibase/types": "2.3.17-alpha.6", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 97ebc2b2e0..8b52e19c87 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "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.3.17-alpha.5", - "@budibase/frontend-core": "2.3.17-alpha.5", - "@budibase/string-templates": "2.3.17-alpha.5", + "@budibase/bbui": "2.3.17-alpha.6", + "@budibase/frontend-core": "2.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.6", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 7a42ba09db..0ef09e42e2 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.5", + "@budibase/bbui": "2.3.17-alpha.6", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 36328c51d8..fc95ba8106 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index c647378d54..5c887c1a5b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "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.3.17-alpha.5", - "@budibase/client": "2.3.17-alpha.5", + "@budibase/backend-core": "2.3.17-alpha.6", + "@budibase/client": "2.3.17-alpha.6", "@budibase/pro": "2.3.17-alpha.5", - "@budibase/string-templates": "2.3.17-alpha.5", - "@budibase/types": "2.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.6", + "@budibase/types": "2.3.17-alpha.6", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index d5eb7e3f04..b53eaf887e 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 0b1ee30b2e..c913fea299 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index c1a1a8a001..a7b280f203 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.5", + "version": "2.3.17-alpha.6", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.5", + "@budibase/backend-core": "2.3.17-alpha.6", "@budibase/pro": "2.3.17-alpha.5", - "@budibase/string-templates": "2.3.17-alpha.5", - "@budibase/types": "2.3.17-alpha.5", + "@budibase/string-templates": "2.3.17-alpha.6", + "@budibase/types": "2.3.17-alpha.6", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From e093ab5ef4992058e4a74181638793ac4b6edd98 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 11:56:26 +0000 Subject: [PATCH 061/273] Update pro version to 2.3.17-alpha.6 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 5c887c1a5b..1d852473f2 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.6", "@budibase/client": "2.3.17-alpha.6", - "@budibase/pro": "2.3.17-alpha.5", + "@budibase/pro": "2.3.17-alpha.6", "@budibase/string-templates": "2.3.17-alpha.6", "@budibase/types": "2.3.17-alpha.6", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 2d6ad91005..72f2bc4db2 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.5.tgz#5bd380c9bf3835694729f1c68c44a77aec7b66dd" - integrity sha512-Nv/BsmItQcdi30oHvNEeRRkDxooMR3shZksb14NDWfdP9gxjVOkUltA2HELujL2ZEg4mismau/0oy9kZy5z3Og== +"@budibase/backend-core@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.6.tgz#b083b3899d435694105d37a1ec817ec6cdc9bb07" + integrity sha512-8ljXZnK6Db3Mexk+MyIsrQBFFu6aV3eRtiw5pwHl9BobxR+6s79YmUgLfjZCfpgzMXqnT73FnV7g8K7KPTNC3g== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.5" + "@budibase/types" "2.3.17-alpha.6" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.5.tgz#4007ab38a5a88cedc1c0ba48543fcbfdf0c58a2a" - integrity sha512-pR7i7ehpoJ08Pq4Xs5vFJcZLvLkfCDS3AvJV1e0j9IDPD73kqiqCxgOF9rE27NTLf0BvbPK5Vj4Z7RPCxIJv7g== +"@budibase/pro@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.6.tgz#2d24afa48003ff5928f667efeff16735bed24e0c" + integrity sha512-yVxKCHiDE4yoARDLZ3IqktUuWgNZoEVlmWo9rS8+bxPcsf5sw7Rj7TXTCMQX7F0cekMVtG+KkpH/8bFrqfR6OA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.5" - "@budibase/types" "2.3.17-alpha.5" + "@budibase/backend-core" "2.3.17-alpha.6" + "@budibase/types" "2.3.17-alpha.6" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.5.tgz#a8c31f49ac9f8b312317fd6fe547ea76d89d059b" - integrity sha512-qp51pVnOaUf42plQjPlCXZVMTIFKrkkhiJ+XaClnekRmyAYaz7JUIex+QTDbmUF4i0WbZRc0MgUCVQxlKkWotA== +"@budibase/types@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.6.tgz#85b148334312a41cfbf01b6a20417b5e20485f3f" + integrity sha512-BgPvLdNQKJSnJmHNo1OfKSHEeVhdTwcNSr2cwHjUpJk394rJiZfsOV7it8M9dLtAtpdsNR3ns7L6biW+pfjYoQ== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index a7b280f203..d595623fa4 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.6", - "@budibase/pro": "2.3.17-alpha.5", + "@budibase/pro": "2.3.17-alpha.6", "@budibase/string-templates": "2.3.17-alpha.6", "@budibase/types": "2.3.17-alpha.6", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 5c534eefe1..3273b78d68 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.5.tgz#5bd380c9bf3835694729f1c68c44a77aec7b66dd" - integrity sha512-Nv/BsmItQcdi30oHvNEeRRkDxooMR3shZksb14NDWfdP9gxjVOkUltA2HELujL2ZEg4mismau/0oy9kZy5z3Og== +"@budibase/backend-core@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.6.tgz#b083b3899d435694105d37a1ec817ec6cdc9bb07" + integrity sha512-8ljXZnK6Db3Mexk+MyIsrQBFFu6aV3eRtiw5pwHl9BobxR+6s79YmUgLfjZCfpgzMXqnT73FnV7g8K7KPTNC3g== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.5" + "@budibase/types" "2.3.17-alpha.6" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.5.tgz#4007ab38a5a88cedc1c0ba48543fcbfdf0c58a2a" - integrity sha512-pR7i7ehpoJ08Pq4Xs5vFJcZLvLkfCDS3AvJV1e0j9IDPD73kqiqCxgOF9rE27NTLf0BvbPK5Vj4Z7RPCxIJv7g== +"@budibase/pro@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.6.tgz#2d24afa48003ff5928f667efeff16735bed24e0c" + integrity sha512-yVxKCHiDE4yoARDLZ3IqktUuWgNZoEVlmWo9rS8+bxPcsf5sw7Rj7TXTCMQX7F0cekMVtG+KkpH/8bFrqfR6OA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.5" - "@budibase/types" "2.3.17-alpha.5" + "@budibase/backend-core" "2.3.17-alpha.6" + "@budibase/types" "2.3.17-alpha.6" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.5": - version "2.3.17-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.5.tgz#a8c31f49ac9f8b312317fd6fe547ea76d89d059b" - integrity sha512-qp51pVnOaUf42plQjPlCXZVMTIFKrkkhiJ+XaClnekRmyAYaz7JUIex+QTDbmUF4i0WbZRc0MgUCVQxlKkWotA== +"@budibase/types@2.3.17-alpha.6": + version "2.3.17-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.6.tgz#85b148334312a41cfbf01b6a20417b5e20485f3f" + integrity sha512-BgPvLdNQKJSnJmHNo1OfKSHEeVhdTwcNSr2cwHjUpJk394rJiZfsOV7it8M9dLtAtpdsNR3ns7L6biW+pfjYoQ== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From e223fae02a47704814481d0feb6c15a7f4125bcc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 12:24:43 +0000 Subject: [PATCH 062/273] Updating types to plurals after discussion about API design. --- packages/types/src/api/web/global/auditLogs.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index ef9927b89a..41bb5f022a 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -3,9 +3,9 @@ import { PaginationResponse, PaginationRequest } from "../" import { User, App } from "../../../" export interface AuditLogSearchParams { - userId?: string[] - appId?: string[] - event?: Event[] + userIds?: string[] + appIds?: string[] + events?: Event[] startDate?: string endDate?: string fullSearch?: string From 0f26f55019679014dc9de10872a15eea2edbb3c0 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 21 Feb 2023 12:31:21 +0000 Subject: [PATCH 063/273] some style updates for the sidebar --- .../_components/ViewDetailsRenderer.svelte | 2 +- .../portal/account/auditLogs/index.svelte | 61 +++++++++++++++---- packages/frontend-core/src/api/auditLogs.js | 6 +- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte index a222871966..b62ee48cb8 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/ViewDetailsRenderer.svelte @@ -10,4 +10,4 @@ } -Edit +Details diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 09b8466d8e..821e504774 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -55,8 +55,10 @@ let prevLogSearch = undefined let selectedUsers = [] let selectedApps = [] + let selectedEvents = [] let selectedLog let sidePanelVisible = false + let wideSidePanel = false let startDate, endDate $: fetchUsers(userPage, userSearchTerm) @@ -66,7 +68,8 @@ startDate, endDate, selectedUsers, - selectedApps + selectedApps, + selectedEvents ) $: userPage = $userPageInfo.page @@ -100,7 +103,8 @@ startDate, endDate, selectedUsers, - selectedApps + selectedApps, + selectedEvents ) => { if ($logsPageInfo.loading) { return @@ -120,6 +124,7 @@ metadataSearch: search, userIds: selectedUsers, appIds: selectedApps, + events: selectedEvents, }) logsPageInfo.fetched( $auditLogs.logs.hasNextPage, @@ -225,7 +230,7 @@ autocomplete placeholder="All apps" label="App" - getOptionValue={app => "app_dev_" + app.appId} + getOptionValue={app => app.instance._id} getOptionLabel={app => app.name} options={$apps} bind:value={selectedApps} @@ -239,6 +244,7 @@ options={Object.entries($auditLogs.events)} placeholder="All events" label="Event" + bind:value={selectedEvents} />
@@ -266,23 +272,35 @@ {#if selectedLog}
{ sidePanelVisible = false }} >
- Audit Logs - { - sidePanelVisible = false - }} - /> + Audit Log +
+ { + wideSidePanel = !wideSidePanel + }} + /> + { + sidePanelVisible = false + }} + /> +
{ const opts = {} @@ -17,8 +17,8 @@ const buildOpts = ({ opts.metadataSearch = metadataSearch } - if (event) { - opts.event = event + if (events) { + opts.event = events } if (userIds) { From a84665c1999a7b683f42794b8fe11c1714ece7d5 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 21 Feb 2023 13:36:14 +0000 Subject: [PATCH 064/273] Re-order deprovisioning sequence to fix platform user removal --- packages/worker/src/sdk/tenants/tenants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/worker/src/sdk/tenants/tenants.ts b/packages/worker/src/sdk/tenants/tenants.ts index 3ba9c3f3a7..829b144c75 100644 --- a/packages/worker/src/sdk/tenants/tenants.ts +++ b/packages/worker/src/sdk/tenants/tenants.ts @@ -5,9 +5,9 @@ import { quotas } from "@budibase/pro" export async function deleteTenant(tenantId: string) { await quotas.bustCache() await platform.tenants.removeTenant(tenantId) - await removeGlobalDB(tenantId) await removeTenantUsers(tenantId) await removeTenantApps(tenantId) + await removeGlobalDB(tenantId) } async function removeGlobalDB(tenantId: string) { From a3dfaf2c3ff6beca2e4a6a86a444cd2461610b7b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 14:39:55 +0000 Subject: [PATCH 065/273] v2.3.17-alpha.7 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 80460af875..2d1b05887b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 68323e05ac..f991cb07bf 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.6", + "@budibase/types": "2.3.17-alpha.7", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index ccaadf77b1..e925115c81 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "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.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.7", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 761f17dd6d..71d498f06e 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.6", - "@budibase/client": "2.3.17-alpha.6", - "@budibase/frontend-core": "2.3.17-alpha.6", - "@budibase/string-templates": "2.3.17-alpha.6", + "@budibase/bbui": "2.3.17-alpha.7", + "@budibase/client": "2.3.17-alpha.7", + "@budibase/frontend-core": "2.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.7", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index a4c21bef29..539612b58e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "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.3.17-alpha.6", - "@budibase/string-templates": "2.3.17-alpha.6", - "@budibase/types": "2.3.17-alpha.6", + "@budibase/backend-core": "2.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.7", + "@budibase/types": "2.3.17-alpha.7", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 8b52e19c87..deea461e50 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "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.3.17-alpha.6", - "@budibase/frontend-core": "2.3.17-alpha.6", - "@budibase/string-templates": "2.3.17-alpha.6", + "@budibase/bbui": "2.3.17-alpha.7", + "@budibase/frontend-core": "2.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.7", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 0ef09e42e2..662771e3bf 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.6", + "@budibase/bbui": "2.3.17-alpha.7", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index fc95ba8106..18a46b71ed 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 1d852473f2..75b8af44e8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "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.3.17-alpha.6", - "@budibase/client": "2.3.17-alpha.6", + "@budibase/backend-core": "2.3.17-alpha.7", + "@budibase/client": "2.3.17-alpha.7", "@budibase/pro": "2.3.17-alpha.6", - "@budibase/string-templates": "2.3.17-alpha.6", - "@budibase/types": "2.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.7", + "@budibase/types": "2.3.17-alpha.7", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index b53eaf887e..8a1024ea0d 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index c913fea299..77b9fba3ca 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index d595623fa4..220bfa239a 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.6", + "version": "2.3.17-alpha.7", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.6", + "@budibase/backend-core": "2.3.17-alpha.7", "@budibase/pro": "2.3.17-alpha.6", - "@budibase/string-templates": "2.3.17-alpha.6", - "@budibase/types": "2.3.17-alpha.6", + "@budibase/string-templates": "2.3.17-alpha.7", + "@budibase/types": "2.3.17-alpha.7", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 91941a538f926f5b9db5bf8032787855cfa13256 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 14:43:54 +0000 Subject: [PATCH 066/273] Update pro version to 2.3.17-alpha.7 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 75b8af44e8..2a2c12e9ba 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.7", "@budibase/client": "2.3.17-alpha.7", - "@budibase/pro": "2.3.17-alpha.6", + "@budibase/pro": "2.3.17-alpha.7", "@budibase/string-templates": "2.3.17-alpha.7", "@budibase/types": "2.3.17-alpha.7", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 72f2bc4db2..0576daf213 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.6.tgz#b083b3899d435694105d37a1ec817ec6cdc9bb07" - integrity sha512-8ljXZnK6Db3Mexk+MyIsrQBFFu6aV3eRtiw5pwHl9BobxR+6s79YmUgLfjZCfpgzMXqnT73FnV7g8K7KPTNC3g== +"@budibase/backend-core@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.7.tgz#a7040a54d9efe6f7e377f06ccdd37c39bafb6098" + integrity sha512-LG6/hP7MH9rkCHhW5D9Awst//tm8fn5Fus1b9nJSFVnNsuobRl0TaVs9A1HOrKr+0yHlLg5OrgLyRuFRxWVP6A== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.6" + "@budibase/types" "2.3.17-alpha.7" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.6.tgz#2d24afa48003ff5928f667efeff16735bed24e0c" - integrity sha512-yVxKCHiDE4yoARDLZ3IqktUuWgNZoEVlmWo9rS8+bxPcsf5sw7Rj7TXTCMQX7F0cekMVtG+KkpH/8bFrqfR6OA== +"@budibase/pro@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.7.tgz#adee25699d0a03f4093256686508c3505fecdeaf" + integrity sha512-mzK3z8v4jJkzUm3v6YeWoMBfFc9lhfk2RXcL3Yn9syCR5eoH+j/b1PVqzb8oHu833MWVHgxEQTguORVciCinig== dependencies: - "@budibase/backend-core" "2.3.17-alpha.6" - "@budibase/types" "2.3.17-alpha.6" + "@budibase/backend-core" "2.3.17-alpha.7" + "@budibase/types" "2.3.17-alpha.7" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.6.tgz#85b148334312a41cfbf01b6a20417b5e20485f3f" - integrity sha512-BgPvLdNQKJSnJmHNo1OfKSHEeVhdTwcNSr2cwHjUpJk394rJiZfsOV7it8M9dLtAtpdsNR3ns7L6biW+pfjYoQ== +"@budibase/types@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.7.tgz#4bad29002bbb01c5987a30ef5c98b7b075a07339" + integrity sha512-mszQPykRp7dPC6MSGZKTeH59Nx282WeqXnTCGi79Kd+Qdrkex5v7fJCdMoGy/gpScVghC0rEDkMTE2BKk6/jMQ== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 220bfa239a..f738df4780 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.7", - "@budibase/pro": "2.3.17-alpha.6", + "@budibase/pro": "2.3.17-alpha.7", "@budibase/string-templates": "2.3.17-alpha.7", "@budibase/types": "2.3.17-alpha.7", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 3273b78d68..d80f39be2c 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.6.tgz#b083b3899d435694105d37a1ec817ec6cdc9bb07" - integrity sha512-8ljXZnK6Db3Mexk+MyIsrQBFFu6aV3eRtiw5pwHl9BobxR+6s79YmUgLfjZCfpgzMXqnT73FnV7g8K7KPTNC3g== +"@budibase/backend-core@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.7.tgz#a7040a54d9efe6f7e377f06ccdd37c39bafb6098" + integrity sha512-LG6/hP7MH9rkCHhW5D9Awst//tm8fn5Fus1b9nJSFVnNsuobRl0TaVs9A1HOrKr+0yHlLg5OrgLyRuFRxWVP6A== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.6" + "@budibase/types" "2.3.17-alpha.7" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.6.tgz#2d24afa48003ff5928f667efeff16735bed24e0c" - integrity sha512-yVxKCHiDE4yoARDLZ3IqktUuWgNZoEVlmWo9rS8+bxPcsf5sw7Rj7TXTCMQX7F0cekMVtG+KkpH/8bFrqfR6OA== +"@budibase/pro@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.7.tgz#adee25699d0a03f4093256686508c3505fecdeaf" + integrity sha512-mzK3z8v4jJkzUm3v6YeWoMBfFc9lhfk2RXcL3Yn9syCR5eoH+j/b1PVqzb8oHu833MWVHgxEQTguORVciCinig== dependencies: - "@budibase/backend-core" "2.3.17-alpha.6" - "@budibase/types" "2.3.17-alpha.6" + "@budibase/backend-core" "2.3.17-alpha.7" + "@budibase/types" "2.3.17-alpha.7" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.6": - version "2.3.17-alpha.6" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.6.tgz#85b148334312a41cfbf01b6a20417b5e20485f3f" - integrity sha512-BgPvLdNQKJSnJmHNo1OfKSHEeVhdTwcNSr2cwHjUpJk394rJiZfsOV7it8M9dLtAtpdsNR3ns7L6biW+pfjYoQ== +"@budibase/types@2.3.17-alpha.7": + version "2.3.17-alpha.7" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.7.tgz#4bad29002bbb01c5987a30ef5c98b7b075a07339" + integrity sha512-mszQPykRp7dPC6MSGZKTeH59Nx282WeqXnTCGi79Kd+Qdrkex5v7fJCdMoGy/gpScVghC0rEDkMTE2BKk6/jMQ== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From b48acd8cf4ad375eb7ae37d219795eb481421cfc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 14:56:38 +0000 Subject: [PATCH 067/273] Some DB type updates (typing dump function) and adding in main audit log event publishers. --- .../src/events/publishers/auditLog.ts | 26 +++++++++++++++++++ .../src/events/publishers/index.ts | 1 + .../types/src/api/web/global/auditLogs.ts | 9 +++++-- packages/types/src/api/web/pagination.ts | 7 +++-- packages/types/src/sdk/db.ts | 15 ++++++++++- packages/types/src/sdk/events/auditLog.ts | 10 +++++++ packages/types/src/sdk/events/event.ts | 8 ++++++ packages/types/src/sdk/events/index.ts | 1 + 8 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 packages/backend-core/src/events/publishers/auditLog.ts create mode 100644 packages/types/src/sdk/events/auditLog.ts diff --git a/packages/backend-core/src/events/publishers/auditLog.ts b/packages/backend-core/src/events/publishers/auditLog.ts new file mode 100644 index 0000000000..b72c135799 --- /dev/null +++ b/packages/backend-core/src/events/publishers/auditLog.ts @@ -0,0 +1,26 @@ +import { + Event, + AuditLogSearchParams, + AuditLogFilterEvent, + AuditLogDownloadEvent, +} from "@budibase/types" +import { publishEvent } from "../events" + +async function filtered(search: AuditLogSearchParams) { + const properties: AuditLogFilterEvent = { + filters: search, + } + await publishEvent(Event.AUDIT_LOG_FILTER, properties) +} + +async function download(search: AuditLogSearchParams) { + const properties: AuditLogDownloadEvent = { + filters: search, + } + await publishEvent(Event.AUDIT_LOG_DOWNLOAD, properties) +} + +export default { + filtered, + download, +} diff --git a/packages/backend-core/src/events/publishers/index.ts b/packages/backend-core/src/events/publishers/index.ts index 34e47b2990..87a34bf3f1 100644 --- a/packages/backend-core/src/events/publishers/index.ts +++ b/packages/backend-core/src/events/publishers/index.ts @@ -21,3 +21,4 @@ export { default as group } from "./group" export { default as plugin } from "./plugin" export { default as backup } from "./backup" export { default as environmentVariable } from "./environmentVariable" +export { default as auditLog } from "./auditLog" diff --git a/packages/types/src/api/web/global/auditLogs.ts b/packages/types/src/api/web/global/auditLogs.ts index 41bb5f022a..8ce0e742d2 100644 --- a/packages/types/src/api/web/global/auditLogs.ts +++ b/packages/types/src/api/web/global/auditLogs.ts @@ -1,5 +1,9 @@ import { Event, AuditedEventFriendlyName } from "../../../sdk" -import { PaginationResponse, PaginationRequest } from "../" +import { + PaginationResponse, + PaginationRequest, + BasicPaginationRequest, +} from "../" import { User, App } from "../../../" export interface AuditLogSearchParams { @@ -9,12 +13,13 @@ export interface AuditLogSearchParams { startDate?: string endDate?: string fullSearch?: string + bookmark?: string } export interface DownloadAuditLogsRequest extends AuditLogSearchParams {} export interface SearchAuditLogsRequest - extends PaginationRequest, + extends BasicPaginationRequest, AuditLogSearchParams {} export enum AuditLogResourceStatus { diff --git a/packages/types/src/api/web/pagination.ts b/packages/types/src/api/web/pagination.ts index ca640d58db..ae4c56971a 100644 --- a/packages/types/src/api/web/pagination.ts +++ b/packages/types/src/api/web/pagination.ts @@ -8,9 +8,12 @@ export enum SortType { number = "number", } -export interface PaginationRequest { - limit?: number +export interface BasicPaginationRequest { bookmark?: string +} + +export interface PaginationRequest extends BasicPaginationRequest { + limit?: number sort?: { order: SortOrder column: string diff --git a/packages/types/src/sdk/db.ts b/packages/types/src/sdk/db.ts index 35d198ccb2..092253d63a 100644 --- a/packages/types/src/sdk/db.ts +++ b/packages/types/src/sdk/db.ts @@ -1,5 +1,6 @@ import Nano from "@budibase/nano" import { AllDocsResponse, AnyDocument, Document } from "../" +import { Writable } from "stream" export type PouchOptions = { inMemory?: boolean @@ -63,6 +64,18 @@ export const isDocument = (doc: any): doc is Document => { return typeof doc === "object" && doc._id && doc._rev } +export interface DatabaseDumpOpts { + filter?: (doc: AnyDocument) => boolean + batch_size?: number + batch_limit?: number + style?: "main_only" | "all_docs" + timeout?: number + doc_ids?: string[] + query_params?: any + view?: string + selector?: any +} + export interface Database { name: string @@ -87,7 +100,7 @@ export interface Database { compact(): Promise // these are all PouchDB related functions that are rarely used - in future // should be replaced by better typed/non-pouch implemented methods - dump(...args: any[]): Promise + dump(stream: Writable, opts?: DatabaseDumpOpts): Promise load(...args: any[]): Promise createIndex(...args: any[]): Promise deleteIndex(...args: any[]): Promise diff --git a/packages/types/src/sdk/events/auditLog.ts b/packages/types/src/sdk/events/auditLog.ts new file mode 100644 index 0000000000..c5e3208536 --- /dev/null +++ b/packages/types/src/sdk/events/auditLog.ts @@ -0,0 +1,10 @@ +import { BaseEvent } from "./event" +import { AuditLogSearchParams } from "../../api" + +export interface AuditLogFilterEvent extends BaseEvent { + filters: AuditLogSearchParams +} + +export interface AuditLogDownloadEvent extends BaseEvent { + filters: AuditLogSearchParams +} diff --git a/packages/types/src/sdk/events/event.ts b/packages/types/src/sdk/events/event.ts index 1be0ea2bdf..119ae4ad7a 100644 --- a/packages/types/src/sdk/events/event.ts +++ b/packages/types/src/sdk/events/event.ts @@ -180,6 +180,10 @@ export enum Event { ENVIRONMENT_VARIABLE_CREATED = "environment_variable:created", ENVIRONMENT_VARIABLE_DELETED = "environment_variable:deleted", ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED = "environment_variable:upgrade_panel_opened", + + // AUDIT LOG + AUDIT_LOG_FILTER = "audit_log:filter", + AUDIT_LOG_DOWNLOAD = "audit_log:download", } // all events that are not audited have been added to this record as undefined, this means @@ -356,6 +360,10 @@ export const AuditedEventFriendlyName: Record = { [Event.INSTALLATION_VERSION_UPGRADED]: undefined, [Event.INSTALLATION_VERSION_DOWNGRADED]: undefined, [Event.INSTALLATION_FIRST_STARTUP]: undefined, + + // AUDIT LOG - NOT AUDITED + [Event.AUDIT_LOG_FILTER]: undefined, + [Event.AUDIT_LOG_DOWNLOAD]: undefined, } // properties added at the final stage of the event pipeline diff --git a/packages/types/src/sdk/events/index.ts b/packages/types/src/sdk/events/index.ts index 009d9beac4..745f84d2a3 100644 --- a/packages/types/src/sdk/events/index.ts +++ b/packages/types/src/sdk/events/index.ts @@ -22,3 +22,4 @@ export * from "./userGroup" export * from "./plugin" export * from "./backup" export * from "./environmentVariable" +export * from "./auditLog" From e64e3a9e458c9f27d2d6a73b8f4821f8120d94d5 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 21 Feb 2023 15:03:58 +0000 Subject: [PATCH 068/273] New Onboarding URL Validation (#9507) * New Onboarding URL Validation * linting * PR Feedback --- .../src/components/start/CreateAppModal.svelte | 16 ++++++++++++++-- .../src/components/start/UpdateAppModal.svelte | 15 +++++++++++++-- packages/builder/src/constants/index.js | 2 +- .../builder/src/helpers/validation/yup/app.js | 4 +--- .../apps/onboarding/_components/NamePanel.svelte | 5 +++++ 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 9ebc046cdc..e3ce048a89 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -26,7 +26,15 @@ const values = writable({ name: "", url: null }) const validation = createValidationStore() - $: validation.check($values) + + $: { + const { name, url } = $values + + validation.check({ + name, + url: url?.[0] === "/" ? url.substring(1, url.length) : url, + }) + } onMount(async () => { const lastChar = $auth.user?.firstName @@ -87,7 +95,11 @@ appValidation.url(validation, { apps: applications }) appValidation.file(validation, { template }) // init validation - validation.check($values) + const { name, url } = $values + validation.check({ + name, + url: url?.[0] === "/" ? url.substring(1, url.length) : url, + }) } async function createNewApp() { diff --git a/packages/builder/src/components/start/UpdateAppModal.svelte b/packages/builder/src/components/start/UpdateAppModal.svelte index a41ebccaeb..4385175816 100644 --- a/packages/builder/src/components/start/UpdateAppModal.svelte +++ b/packages/builder/src/components/start/UpdateAppModal.svelte @@ -23,14 +23,25 @@ }) const validation = createValidationStore() - $: validation.check($values) + $: { + const { name, url } = $values + + validation.check({ + name, + url: url?.[0] === "/" ? url.substring(1, url.length) : url, + }) + } const setupValidation = async () => { const applications = svelteGet(apps) appValidation.name(validation, { apps: applications, currentApp: app }) appValidation.url(validation, { apps: applications, currentApp: app }) // init validation - validation.check($values) + const { name, url } = $values + validation.check({ + name, + url: url?.[0] === "/" ? url.substring(1, url.length) : url, + }) } async function updateApp() { diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index 803cafcffb..f68202f81e 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -46,7 +46,7 @@ export const LAYOUT_NAMES = { // one or more word characters and whitespace export const APP_NAME_REGEX = /^[\w\s]+$/ // zero or more non-whitespace characters -export const APP_URL_REGEX = /^\S*$/ +export const APP_URL_REGEX = /^[0-9a-zA-Z-_]+$/ export const DefaultAppTheme = { primaryColor: "var(--spectrum-global-color-blue-600)", diff --git a/packages/builder/src/helpers/validation/yup/app.js b/packages/builder/src/helpers/validation/yup/app.js index 4e41576d46..8498255cc9 100644 --- a/packages/builder/src/helpers/validation/yup/app.js +++ b/packages/builder/src/helpers/validation/yup/app.js @@ -62,11 +62,9 @@ export const url = (validation, { apps, currentApp } = { apps: [] }) => { } // make it clear that this is a url path and cannot be a full url return ( - value.startsWith("/") && !value.includes("http") && !value.includes("www") && - !value.includes(".") && - value.length > 1 // just '/' is not valid + !value.includes(".") ) }) ) diff --git a/packages/builder/src/pages/builder/portal/apps/onboarding/_components/NamePanel.svelte b/packages/builder/src/pages/builder/portal/apps/onboarding/_components/NamePanel.svelte index 730cfbe4a2..1264b63531 100644 --- a/packages/builder/src/pages/builder/portal/apps/onboarding/_components/NamePanel.svelte +++ b/packages/builder/src/pages/builder/portal/apps/onboarding/_components/NamePanel.svelte @@ -1,6 +1,7 @@ From 5e7305b4dd302180b179145c89239778d60b7286 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 21 Feb 2023 15:04:37 +0000 Subject: [PATCH 069/273] Fix Automation Bindings Panel Requiring a Double Click (#9688) * Fix Automation Bindings Panel Requiring a Double Click * PR Feedback --------- Co-authored-by: Rory Powell --- .../builder/src/components/common/bindings/BindingPanel.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/builder/src/components/common/bindings/BindingPanel.svelte b/packages/builder/src/components/common/bindings/BindingPanel.svelte index 7daf2173a7..3a1c6c4fee 100644 --- a/packages/builder/src/components/common/bindings/BindingPanel.svelte +++ b/packages/builder/src/components/common/bindings/BindingPanel.svelte @@ -183,6 +183,7 @@ bind:this={popover} anchor={popoverAnchor} maxWidth={300} + dismissible={false} >
From 9fadc42a2e62d472aeea4fdd7fd5c141319b9818 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 15:20:48 +0000 Subject: [PATCH 070/273] v2.3.17-alpha.8 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 2d1b05887b..5530ace9f0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index f991cb07bf..18fcb3d696 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.17-alpha.7", + "@budibase/types": "2.3.17-alpha.8", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index e925115c81..3144341c74 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "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.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.8", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 71d498f06e..54b6994eb7 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.17-alpha.7", - "@budibase/client": "2.3.17-alpha.7", - "@budibase/frontend-core": "2.3.17-alpha.7", - "@budibase/string-templates": "2.3.17-alpha.7", + "@budibase/bbui": "2.3.17-alpha.8", + "@budibase/client": "2.3.17-alpha.8", + "@budibase/frontend-core": "2.3.17-alpha.8", + "@budibase/string-templates": "2.3.17-alpha.8", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 539612b58e..83b9440102 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "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.3.17-alpha.7", - "@budibase/string-templates": "2.3.17-alpha.7", - "@budibase/types": "2.3.17-alpha.7", + "@budibase/backend-core": "2.3.17-alpha.8", + "@budibase/string-templates": "2.3.17-alpha.8", + "@budibase/types": "2.3.17-alpha.8", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index deea461e50..a0ea947f18 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "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.3.17-alpha.7", - "@budibase/frontend-core": "2.3.17-alpha.7", - "@budibase/string-templates": "2.3.17-alpha.7", + "@budibase/bbui": "2.3.17-alpha.8", + "@budibase/frontend-core": "2.3.17-alpha.8", + "@budibase/string-templates": "2.3.17-alpha.8", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 662771e3bf..6ddf874931 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.17-alpha.7", + "@budibase/bbui": "2.3.17-alpha.8", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 18a46b71ed..cd007bac7e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 2a2c12e9ba..3436419c98 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "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.3.17-alpha.7", - "@budibase/client": "2.3.17-alpha.7", + "@budibase/backend-core": "2.3.17-alpha.8", + "@budibase/client": "2.3.17-alpha.8", "@budibase/pro": "2.3.17-alpha.7", - "@budibase/string-templates": "2.3.17-alpha.7", - "@budibase/types": "2.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.8", + "@budibase/types": "2.3.17-alpha.8", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 8a1024ea0d..e7a72c35e5 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 77b9fba3ca..8db1b0708c 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index f738df4780..ecb62ceeb5 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17-alpha.7", + "version": "2.3.17-alpha.8", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.17-alpha.7", + "@budibase/backend-core": "2.3.17-alpha.8", "@budibase/pro": "2.3.17-alpha.7", - "@budibase/string-templates": "2.3.17-alpha.7", - "@budibase/types": "2.3.17-alpha.7", + "@budibase/string-templates": "2.3.17-alpha.8", + "@budibase/types": "2.3.17-alpha.8", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 1ada790d507b76e4d2cb133a98465dc07b0b1b36 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:21:00 +0000 Subject: [PATCH 071/273] Fix postgres update for relationships --- packages/server/src/integrations/base/sql.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e66795a6db..c722891910 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,9 +502,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query - .update(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.update(parsedBody).returning("*") } } From fcab5884ac85d21067c85b15fc8782825bb36838 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 15:24:40 +0000 Subject: [PATCH 072/273] Update pro version to 2.3.17-alpha.8 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 3436419c98..63629b425a 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.17-alpha.8", "@budibase/client": "2.3.17-alpha.8", - "@budibase/pro": "2.3.17-alpha.7", + "@budibase/pro": "2.3.17-alpha.8", "@budibase/string-templates": "2.3.17-alpha.8", "@budibase/types": "2.3.17-alpha.8", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 0576daf213..be01941673 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.7.tgz#a7040a54d9efe6f7e377f06ccdd37c39bafb6098" - integrity sha512-LG6/hP7MH9rkCHhW5D9Awst//tm8fn5Fus1b9nJSFVnNsuobRl0TaVs9A1HOrKr+0yHlLg5OrgLyRuFRxWVP6A== +"@budibase/backend-core@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.8.tgz#c1bd7bb9ac581bd4ea9eb0e7883553219e3bcd9f" + integrity sha512-31zNXAwukBpbcHSvobtdTLBtrZsfIsq0NilxHzFJpaMEeGSq47fpwGPkzvzoekhgn0oGs0X4m4uRNaFKEDifeQ== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.7" + "@budibase/types" "2.3.17-alpha.8" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.7.tgz#adee25699d0a03f4093256686508c3505fecdeaf" - integrity sha512-mzK3z8v4jJkzUm3v6YeWoMBfFc9lhfk2RXcL3Yn9syCR5eoH+j/b1PVqzb8oHu833MWVHgxEQTguORVciCinig== +"@budibase/pro@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.8.tgz#f88416061c097c12ed133fac59200da408223c1c" + integrity sha512-d8VVdaH6X1e/GrQB4xA09pN5ANk6mxbXJ861KEniex3uEl1YFBJ75JJvoPLf2ynRIVqqsix18AXoO76ug7m9zA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.7" - "@budibase/types" "2.3.17-alpha.7" + "@budibase/backend-core" "2.3.17-alpha.8" + "@budibase/types" "2.3.17-alpha.8" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.7.tgz#4bad29002bbb01c5987a30ef5c98b7b075a07339" - integrity sha512-mszQPykRp7dPC6MSGZKTeH59Nx282WeqXnTCGi79Kd+Qdrkex5v7fJCdMoGy/gpScVghC0rEDkMTE2BKk6/jMQ== +"@budibase/types@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.8.tgz#3ac692eec686c7b1ca728774a5a7e171644a9388" + integrity sha512-Ubt1vsa2OJY9NYqIxKrrvokAkWNs9snHR69czBkyigYnRrQ8axXijn3s3DoxhXg0KEyaFeMcOnq1yxEyHXPDBg== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index ecb62ceeb5..e7fe5de7f4 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.17-alpha.8", - "@budibase/pro": "2.3.17-alpha.7", + "@budibase/pro": "2.3.17-alpha.8", "@budibase/string-templates": "2.3.17-alpha.8", "@budibase/types": "2.3.17-alpha.8", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index d80f39be2c..fdf89c6b1c 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.7.tgz#a7040a54d9efe6f7e377f06ccdd37c39bafb6098" - integrity sha512-LG6/hP7MH9rkCHhW5D9Awst//tm8fn5Fus1b9nJSFVnNsuobRl0TaVs9A1HOrKr+0yHlLg5OrgLyRuFRxWVP6A== +"@budibase/backend-core@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17-alpha.8.tgz#c1bd7bb9ac581bd4ea9eb0e7883553219e3bcd9f" + integrity sha512-31zNXAwukBpbcHSvobtdTLBtrZsfIsq0NilxHzFJpaMEeGSq47fpwGPkzvzoekhgn0oGs0X4m4uRNaFKEDifeQ== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.17-alpha.7" + "@budibase/types" "2.3.17-alpha.8" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.7.tgz#adee25699d0a03f4093256686508c3505fecdeaf" - integrity sha512-mzK3z8v4jJkzUm3v6YeWoMBfFc9lhfk2RXcL3Yn9syCR5eoH+j/b1PVqzb8oHu833MWVHgxEQTguORVciCinig== +"@budibase/pro@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17-alpha.8.tgz#f88416061c097c12ed133fac59200da408223c1c" + integrity sha512-d8VVdaH6X1e/GrQB4xA09pN5ANk6mxbXJ861KEniex3uEl1YFBJ75JJvoPLf2ynRIVqqsix18AXoO76ug7m9zA== dependencies: - "@budibase/backend-core" "2.3.17-alpha.7" - "@budibase/types" "2.3.17-alpha.7" + "@budibase/backend-core" "2.3.17-alpha.8" + "@budibase/types" "2.3.17-alpha.8" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17-alpha.7": - version "2.3.17-alpha.7" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.7.tgz#4bad29002bbb01c5987a30ef5c98b7b075a07339" - integrity sha512-mszQPykRp7dPC6MSGZKTeH59Nx282WeqXnTCGi79Kd+Qdrkex5v7fJCdMoGy/gpScVghC0rEDkMTE2BKk6/jMQ== +"@budibase/types@2.3.17-alpha.8": + version "2.3.17-alpha.8" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17-alpha.8.tgz#3ac692eec686c7b1ca728774a5a7e171644a9388" + integrity sha512-Ubt1vsa2OJY9NYqIxKrrvokAkWNs9snHR69czBkyigYnRrQ8axXijn3s3DoxhXg0KEyaFeMcOnq1yxEyHXPDBg== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From e0b3976ee4338b543765bf6952726bae509606df Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:57:04 +0000 Subject: [PATCH 073/273] Add return select statement back on update --- packages/server/src/integrations/base/sql.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c722891910..e66795a6db 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,7 +502,9 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query.update(parsedBody).returning("*") + return query + .update(parsedBody) + .returning(generateSelectStatement(json, knex)) } } From be81767a465af3edd7c90514f42c0b8f28d2b0d0 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 15:57:56 +0000 Subject: [PATCH 074/273] Replace maps for foreach --- packages/server/src/api/controllers/row/ExternalRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 2faff95595..6e79971aa2 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -293,7 +293,7 @@ export class ExternalRequest { // we're not inserting a doc, will be a bunch of update calls const otherKey: string = field.throughFrom || linkTablePrimary const thisKey: string = field.throughTo || tablePrimary - row[key].map((relationship: any) => { + row[key].forEach((relationship: any) => { manyRelationships.push({ tableId: field.through || field.tableId, isUpdate: false, @@ -309,7 +309,7 @@ export class ExternalRequest { const thisKey: string = "id" // @ts-ignore const otherKey: string = field.fieldName - row[key].map((relationship: any) => { + row[key].forEach((relationship: any) => { manyRelationships.push({ tableId: field.tableId, isUpdate: true, From e0242d08832bfa25167c050780f5ed16b76405b2 Mon Sep 17 00:00:00 2001 From: adrinr Date: Tue, 21 Feb 2023 16:29:18 +0000 Subject: [PATCH 075/273] Fix the many to one updates --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 6e79971aa2..f62e7fe2d0 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -316,7 +316,7 @@ export class ExternalRequest { key: otherKey, [thisKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later - [otherKey]: `{{ literal ${tablePrimary} }}`, + [otherKey]: `{{ literal [${table.name}.${tablePrimary}] }}`, }) }) } From ccc17f55994c05226d8bca3a437494a4201f3a82 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 17:03:45 +0000 Subject: [PATCH 076/273] v2.3.18-alpha.0 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index cfbed56e23..a881722de6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.17", + "version": "2.3.18-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 32961a060b..c03600f5da 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "^2.3.17", + "@budibase/types": "2.3.18-alpha.0", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 8c9629b314..9e3aea5fea 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "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.3.17", + "@budibase/string-templates": "2.3.18-alpha.0", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 5e968c23a3..f8f6ac289d 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "^2.3.17", - "@budibase/client": "^2.3.17", - "@budibase/frontend-core": "^2.3.17", - "@budibase/string-templates": "^2.3.17", + "@budibase/bbui": "2.3.18-alpha.0", + "@budibase/client": "2.3.18-alpha.0", + "@budibase/frontend-core": "2.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.0", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index fb08c290fc..f2044f9c8b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "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.3.17", - "@budibase/string-templates": "^2.3.17", - "@budibase/types": "^2.3.17", + "@budibase/backend-core": "2.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.0", + "@budibase/types": "2.3.18-alpha.0", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 78df2b67f7..a784cfa6bc 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.17", + "version": "2.3.18-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": "^2.3.17", - "@budibase/frontend-core": "^2.3.17", - "@budibase/string-templates": "^2.3.17", + "@budibase/bbui": "2.3.18-alpha.0", + "@budibase/frontend-core": "2.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.0", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 502df0fbd4..b0d39ed450 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "^2.3.17", + "@budibase/bbui": "2.3.18-alpha.0", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index d8a5c44c5b..597c3dff84 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 0ddf85f40f..8fe938e72c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "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.3.17", - "@budibase/client": "^2.3.17", + "@budibase/backend-core": "2.3.18-alpha.0", + "@budibase/client": "2.3.18-alpha.0", "@budibase/pro": "2.3.17", - "@budibase/string-templates": "^2.3.17", - "@budibase/types": "^2.3.17", + "@budibase/string-templates": "2.3.18-alpha.0", + "@budibase/types": "2.3.18-alpha.0", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 87b7c69dbb..edae9518ca 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 8417cadc06..3153bad674 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index cd25468c6b..1584019514 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.17", + "version": "2.3.18-alpha.0", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "^2.3.17", + "@budibase/backend-core": "2.3.18-alpha.0", "@budibase/pro": "2.3.17", - "@budibase/string-templates": "^2.3.17", - "@budibase/types": "^2.3.17", + "@budibase/string-templates": "2.3.18-alpha.0", + "@budibase/types": "2.3.18-alpha.0", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 1742055c3cee7c91b5b27489066db5e827d8a07b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 17:07:51 +0000 Subject: [PATCH 077/273] Update pro version to 2.3.18-alpha.0 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 45 ++++++++++++++++++---------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 58 ++++++++++++++++++------------------ 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 8fe938e72c..5812a84717 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.0", "@budibase/client": "2.3.18-alpha.0", - "@budibase/pro": "2.3.17", + "@budibase/pro": "2.3.18-alpha.0", "@budibase/string-templates": "2.3.18-alpha.0", "@budibase/types": "2.3.18-alpha.0", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 95d377f24a..4d31641d3f 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,13 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17.tgz#27c8c2144bfda1533b43da6de7111c0819aea6a5" - integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== +"@budibase/backend-core@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.0.tgz#c0a64a150c1fef9cc69f95f0aece4e857d64438d" + integrity sha512-ugD+WMoFwpXm+moSLHUgaBOu4XpX0+5UhmMWcNeRtH0Yd9GpDh2QzwtoN8BtXq8k5gkVEyoNSz+6oxKfNkNVdQ== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.17" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.18-alpha.0" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1309,7 +1310,6 @@ posthog-node "1.3.0" pouchdb "7.3.0" pouchdb-find "7.2.2" - pouchdb-replication-stream "1.2.9" redlock "4.2.0" sanitize-s3-objectkey "0.0.1" semver "7.3.7" @@ -1379,13 +1379,26 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17.tgz#1a05d3d13195fcfacac410305fcd0943fbbcd5c8" - integrity sha512-sdWuKRDbseu2POkyGfmiqAWp8M9jGmpD0FqaIEWGQmKdezvOKh3sGg0PGT4InoibbXcFf4vVB+HiofBedDFLkA== +"@budibase/pouchdb-replication-stream@1.2.10": + version "1.2.10" + resolved "https://registry.yarnpkg.com/@budibase/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.10.tgz#4100df2effd7c823edadddcdbdc380f6827eebf5" + integrity sha512-1zeorOwbelZ7HF5vFB+pKE8Mnh31om8k1M6T3AZXVULYTHLsyJrMTozSv5CJ1P8ZfOIJab09HDzCXDh2icFekg== dependencies: - "@budibase/backend-core" "2.3.17" - "@budibase/types" "2.3.17" + argsarray "0.0.1" + inherits "^2.0.3" + lodash.pick "^4.0.0" + ndjson "^1.4.3" + pouch-stream "^0.4.0" + pouchdb-promise "^6.0.4" + through2 "^2.0.0" + +"@budibase/pro@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.0.tgz#e87a2449d9e2453766c0ea77539af359bf5a81ff" + integrity sha512-nKLhCdLxmBX+VY7LF6daH0/AItcHoQTmBB3tc0SP7y4OLcJZfBEYidoWqWJKCgdz6LScWWogLgbDIAC8t+LNzg== + dependencies: + "@budibase/backend-core" "2.3.18-alpha.0" + "@budibase/types" "2.3.18-alpha.0" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1411,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.17", "@budibase/types@^2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17.tgz#d97c1de5fb03c91ff7e55d7c8c3901e5e2e95995" - integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== +"@budibase/types@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.0.tgz#14480e760c9e7931e884e9e0f8b1d5dd7e5d91c9" + integrity sha512-d+OcW2sNYw7VthMGrOBRY2Bz6iPQVWOnJ94XfYlBRJVIoYwBgudbYkOXPz/vQmHyjSUQFobrvs6UDeZ/3VJTaA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 1584019514..9fd2843ae4 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.0", - "@budibase/pro": "2.3.17", + "@budibase/pro": "2.3.18-alpha.0", "@budibase/string-templates": "2.3.18-alpha.0", "@budibase/types": "2.3.18-alpha.0", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 5c73052232..83417a2e84 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,13 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.17.tgz#27c8c2144bfda1533b43da6de7111c0819aea6a5" - integrity sha512-KcmF2OrNLjLbFtNbYD4ZufnsnwmN2Ez/occgWiecvFRAHOhpkm+Hoy6VggpG1YJBp1DG9kLh3WAZbeYI3QoJbw== +"@budibase/backend-core@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.0.tgz#c0a64a150c1fef9cc69f95f0aece4e857d64438d" + integrity sha512-ugD+WMoFwpXm+moSLHUgaBOu4XpX0+5UhmMWcNeRtH0Yd9GpDh2QzwtoN8BtXq8k5gkVEyoNSz+6oxKfNkNVdQ== dependencies: "@budibase/nano" "10.1.1" - "@budibase/types" "^2.3.17" + "@budibase/pouchdb-replication-stream" "1.2.10" + "@budibase/types" "2.3.18-alpha.0" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -506,7 +507,6 @@ posthog-node "1.3.0" pouchdb "7.3.0" pouchdb-find "7.2.2" - pouchdb-replication-stream "1.2.9" redlock "4.2.0" sanitize-s3-objectkey "0.0.1" semver "7.3.7" @@ -526,13 +526,26 @@ qs "^6.11.0" tough-cookie "^4.1.2" -"@budibase/pro@2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.17.tgz#1a05d3d13195fcfacac410305fcd0943fbbcd5c8" - integrity sha512-sdWuKRDbseu2POkyGfmiqAWp8M9jGmpD0FqaIEWGQmKdezvOKh3sGg0PGT4InoibbXcFf4vVB+HiofBedDFLkA== +"@budibase/pouchdb-replication-stream@1.2.10": + version "1.2.10" + resolved "https://registry.yarnpkg.com/@budibase/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.10.tgz#4100df2effd7c823edadddcdbdc380f6827eebf5" + integrity sha512-1zeorOwbelZ7HF5vFB+pKE8Mnh31om8k1M6T3AZXVULYTHLsyJrMTozSv5CJ1P8ZfOIJab09HDzCXDh2icFekg== dependencies: - "@budibase/backend-core" "2.3.17" - "@budibase/types" "2.3.17" + argsarray "0.0.1" + inherits "^2.0.3" + lodash.pick "^4.0.0" + ndjson "^1.4.3" + pouch-stream "^0.4.0" + pouchdb-promise "^6.0.4" + through2 "^2.0.0" + +"@budibase/pro@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.0.tgz#e87a2449d9e2453766c0ea77539af359bf5a81ff" + integrity sha512-nKLhCdLxmBX+VY7LF6daH0/AItcHoQTmBB3tc0SP7y4OLcJZfBEYidoWqWJKCgdz6LScWWogLgbDIAC8t+LNzg== + dependencies: + "@budibase/backend-core" "2.3.18-alpha.0" + "@budibase/types" "2.3.18-alpha.0" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -540,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.17", "@budibase/types@^2.3.17": - version "2.3.17" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.17.tgz#d97c1de5fb03c91ff7e55d7c8c3901e5e2e95995" - integrity sha512-p/6WgwNjVGfwyNLOofhPEG7S3tt5URxAVs+mPXuLn5bsAqRxxJ5XObvw8chijYXmewhGP0hjONQDkmDJ0FkHuA== +"@budibase/types@2.3.18-alpha.0": + version "2.3.18-alpha.0" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.0.tgz#14480e760c9e7931e884e9e0f8b1d5dd7e5d91c9" + integrity sha512-d+OcW2sNYw7VthMGrOBRY2Bz6iPQVWOnJ94XfYlBRJVIoYwBgudbYkOXPz/vQmHyjSUQFobrvs6UDeZ/3VJTaA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" @@ -6780,19 +6793,6 @@ pouchdb-promise@6.4.3, pouchdb-promise@^6.0.4: dependencies: lie "3.1.1" -pouchdb-replication-stream@1.2.9: - version "1.2.9" - resolved "https://registry.yarnpkg.com/pouchdb-replication-stream/-/pouchdb-replication-stream-1.2.9.tgz#aa4fa5d8f52df4825392f18e07c7e11acffc650a" - integrity sha512-hM8XRBfamTTUwRhKwLS/jSNouBhn9R/4ugdHNRD1EvJzwV8iImh6sDYbCU9PGuznjyOjXz6vpFRzKeI2KYfwnQ== - dependencies: - argsarray "0.0.1" - inherits "^2.0.3" - lodash.pick "^4.0.0" - ndjson "^1.4.3" - pouch-stream "^0.4.0" - pouchdb-promise "^6.0.4" - through2 "^2.0.0" - pouchdb-selector-core@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz#264d7436a8c8ac3801f39960e79875ef7f3879a0" From 940de8b6a0a6e013b95852e7d8268b205150f371 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 21 Feb 2023 17:13:24 +0000 Subject: [PATCH 078/273] Run CI steps in parallel (#9760) * Parallel CI * Add build to integration test * Add checkout to top of each run * Revert branch update for ci job * Experiment with --runInBand for CI * Fix intermittent backend-core migration test failure * Fix hanging worker redis connection * Update naming from reset to newTenant --- .github/workflows/budibase_ci.yml | 94 ++++++++------ .husky/pre-commit | 2 - packages/backend-core/jest.config.ts | 10 +- packages/backend-core/package.json | 2 +- .../passport/sso/tests/google.spec.ts | 2 +- .../backend-core/src/migrations/migrations.ts | 116 +++++++++--------- ...x.spec.js.snap => migrations.spec.ts.snap} | 0 .../src/migrations/tests/index.spec.js | 57 --------- .../src/migrations/tests/migrations.spec.ts | 64 ++++++++++ packages/backend-core/src/redis/init.ts | 6 +- packages/backend-core/src/redis/redis.ts | 5 + .../tests/utilities/DBTestConfiguration.ts | 4 + packages/server/jest.config.ts | 21 ++-- packages/server/package.json | 2 +- packages/server/specs/resources/query.js | 2 +- packages/server/specs/resources/table.js | 2 +- .../src/api/routes/tests/static.spec.js | 12 -- .../server/src/api/routes/tests/user.spec.js | 5 +- packages/server/src/utilities/redis.ts | 2 + packages/worker/jest.config.ts | 25 ++-- packages/worker/package.json | 2 +- packages/worker/src/utilities/redis.ts | 2 + 22 files changed, 227 insertions(+), 210 deletions(-) rename packages/backend-core/src/migrations/tests/__snapshots__/{index.spec.js.snap => migrations.spec.ts.snap} (100%) delete mode 100644 packages/backend-core/src/migrations/tests/index.spec.js create mode 100644 packages/backend-core/src/migrations/tests/migrations.spec.ts diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index c07f9b2c28..e0263546ff 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -11,7 +11,6 @@ on: branches: - master - develop - - release workflow_dispatch: env: @@ -20,9 +19,53 @@ env: PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }} jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + - run: yarn + - run: yarn lint + build: runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Install Pro + run: yarn install:pro $BRANCH $BASE_BRANCH + - run: yarn + - run: yarn bootstrap + - run: yarn build + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Install Pro + run: yarn install:pro $BRANCH $BASE_BRANCH + - run: yarn + - run: yarn bootstrap + - run: yarn test + - uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos + files: ./packages/server/coverage/clover.xml,./packages/worker/coverage/clover.xml,./packages/backend-core/coverage/clover.xml + name: codecov-umbrella + verbose: true + + integration-test: + runs-on: ubuntu-latest services: couchdb: image: ibmcom/couchdb3 @@ -31,39 +74,18 @@ jobs: COUCHDB_USER: budibase ports: - 4567:5984 - - strategy: - matrix: - node-version: [14.x] - steps: - - uses: actions/checkout@v2 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install Pro - run: yarn install:pro $BRANCH $BASE_BRANCH - - - run: yarn - - run: yarn bootstrap - - run: yarn lint - - run: yarn build - - run: yarn test - env: - CI: true - name: Budibase CI - - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos - files: ./packages/server/coverage/clover.xml,./packages/worker/coverage/clover.xml,./packages/backend-core/coverage/clover.xml - name: codecov-umbrella - verbose: true - - - name: QA Core Integration Tests - run: | - cd qa-core - yarn - yarn api:test:ci \ No newline at end of file + - uses: actions/checkout@v2 + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Install Pro + run: yarn install:pro $BRANCH $BASE_BRANCH + - run: yarn + - run: yarn bootstrap + - run: yarn build + - run: | + cd qa-core + yarn + yarn api:test:ci diff --git a/.husky/pre-commit b/.husky/pre-commit index 3b614330e0..6700f51282 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,2 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" - -yarn run lint diff --git a/packages/backend-core/jest.config.ts b/packages/backend-core/jest.config.ts index 0483fb073a..1e69797e71 100644 --- a/packages/backend-core/jest.config.ts +++ b/packages/backend-core/jest.config.ts @@ -9,15 +9,9 @@ const baseConfig: Config.InitialProjectOptions = { transform: { "^.+\\.ts?$": "@swc/jest", }, -} - -if (!process.env.CI) { - // use sources when not in CI - baseConfig.moduleNameMapper = { + moduleNameMapper: { "@budibase/types": "/../types/src", - } -} else { - console.log("Running tests with compiled dependency sources") + }, } const config: Config.InitialOptions = { diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index c03600f5da..a32f5fd4dd 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -18,7 +18,7 @@ "build:pro": "../../scripts/pro/build.sh", "postbuild": "yarn run build:pro", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", - "test": "jest --coverage", + "test": "jest --coverage --runInBand", "test:watch": "jest --watchAll" }, "dependencies": { diff --git a/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts b/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts index eb8ffc9b71..d0689a1f0a 100644 --- a/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts +++ b/packages/backend-core/src/middleware/passport/sso/tests/google.spec.ts @@ -19,7 +19,7 @@ describe("google", () => { const callbackUrl = generator.url() it("should create successfully create a google strategy", async () => { - await google.strategyFactory(googleConfig, callbackUrl) + await google.strategyFactory(googleConfig, callbackUrl, mockSaveUserFn) const expectedOptions = { clientID: googleConfig.clientID, diff --git a/packages/backend-core/src/migrations/migrations.ts b/packages/backend-core/src/migrations/migrations.ts index 79c7eb55ea..2e3524775f 100644 --- a/packages/backend-core/src/migrations/migrations.ts +++ b/packages/backend-core/src/migrations/migrations.ts @@ -4,7 +4,7 @@ import { StaticDatabases, getAllApps, getGlobalDBName, - doWithDB, + getDB, } from "../db" import environment from "../environment" import * as platform from "../platform" @@ -86,66 +86,65 @@ export const runMigration = async ( count++ const lengthStatement = length > 1 ? `[${count}/${length}]` : "" - await doWithDB(dbName, async (db: any) => { - try { - const doc = await getMigrationsDoc(db) + const db = getDB(dbName) + try { + const doc = await getMigrationsDoc(db) - // the migration has already been run - if (doc[migrationName]) { - // check for force - if ( - options.force && - options.force[migrationType] && - options.force[migrationType].includes(migrationName) - ) { - log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Forcing` - ) - } else { - // no force, exit - return - } - } - - // check if the migration is not a no-op - if (!options.noOp) { + // the migration has already been run + if (doc[migrationName]) { + // check for force + if ( + options.force && + options.force[migrationType] && + options.force[migrationType].includes(migrationName) + ) { log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Running ${lengthStatement}` - ) - - if (migration.preventRetry) { - // eagerly set the completion date - // so that we never run this migration twice even upon failure - doc[migrationName] = Date.now() - const response = await db.put(doc) - doc._rev = response.rev - } - - // run the migration - if (migrationType === MigrationType.APP) { - await context.doInAppContext(db.name, async () => { - await migration.fn(db) - }) - } else { - await migration.fn(db) - } - - log( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Complete` + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Forcing` ) + } else { + // no force, exit + return } - - // mark as complete - doc[migrationName] = Date.now() - await db.put(doc) - } catch (err) { - console.error( - `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Error: `, - err - ) - throw err } - }) + + // check if the migration is not a no-op + if (!options.noOp) { + log( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Running ${lengthStatement}` + ) + + if (migration.preventRetry) { + // eagerly set the completion date + // so that we never run this migration twice even upon failure + doc[migrationName] = Date.now() + const response = await db.put(doc) + doc._rev = response.rev + } + + // run the migration + if (migrationType === MigrationType.APP) { + await context.doInAppContext(db.name, async () => { + await migration.fn(db) + }) + } else { + await migration.fn(db) + } + + log( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Complete` + ) + } + + // mark as complete + doc[migrationName] = Date.now() + await db.put(doc) + } catch (err) { + console.error( + `[Tenant: ${tenantId}] [Migration: ${migrationName}] [DB: ${dbName}] Error: `, + err + ) + throw err + } } } @@ -185,7 +184,10 @@ export const runMigrations = async ( // for all migrations for (const migration of migrations) { // run the migration - await context.doInTenant(tenantId, () => runMigration(migration, options)) + await context.doInTenant( + tenantId, + async () => await runMigration(migration, options) + ) } } console.log("Migrations complete") diff --git a/packages/backend-core/src/migrations/tests/__snapshots__/index.spec.js.snap b/packages/backend-core/src/migrations/tests/__snapshots__/migrations.spec.ts.snap similarity index 100% rename from packages/backend-core/src/migrations/tests/__snapshots__/index.spec.js.snap rename to packages/backend-core/src/migrations/tests/__snapshots__/migrations.spec.ts.snap diff --git a/packages/backend-core/src/migrations/tests/index.spec.js b/packages/backend-core/src/migrations/tests/index.spec.js deleted file mode 100644 index c1915510c3..0000000000 --- a/packages/backend-core/src/migrations/tests/index.spec.js +++ /dev/null @@ -1,57 +0,0 @@ -require("../../../tests") -const { runMigrations, getMigrationsDoc } = require("../index") -const { getGlobalDBName, getDB } = require("../../db") - -const { structures, testEnv } = require("../../../tests") -testEnv.multiTenant() - -let db - -describe("migrations", () => { - - const migrationFunction = jest.fn() - - const MIGRATIONS = [{ - type: "global", - name: "test", - fn: migrationFunction - }] - - let tenantId - - beforeEach(() => { - tenantId = structures.tenant.id() - db = getDB(getGlobalDBName(tenantId)) - }) - - afterEach(async () => { - jest.clearAllMocks() - await db.destroy() - }) - - const migrate = () => { - return runMigrations(MIGRATIONS, { tenantIds: [tenantId]}) - } - - it("should run a new migration", async () => { - await migrate() - expect(migrationFunction).toHaveBeenCalled() - const doc = await getMigrationsDoc(db) - expect(doc.test).toBeDefined() - }) - - it("should match snapshot", async () => { - await migrate() - const doc = await getMigrationsDoc(db) - expect(doc).toMatchSnapshot() - }) - - it("should skip a previously run migration", async () => { - await migrate() - const previousMigrationTime = await getMigrationsDoc(db).test - await migrate() - const currentMigrationTime = await getMigrationsDoc(db).test - expect(migrationFunction).toHaveBeenCalledTimes(1) - expect(currentMigrationTime).toBe(previousMigrationTime) - }) -}) \ No newline at end of file diff --git a/packages/backend-core/src/migrations/tests/migrations.spec.ts b/packages/backend-core/src/migrations/tests/migrations.spec.ts new file mode 100644 index 0000000000..c74ab816c1 --- /dev/null +++ b/packages/backend-core/src/migrations/tests/migrations.spec.ts @@ -0,0 +1,64 @@ +import { testEnv, DBTestConfiguration } from "../../../tests" +import * as migrations from "../index" +import * as context from "../../context" +import { MigrationType } from "@budibase/types" + +testEnv.multiTenant() + +describe("migrations", () => { + const config = new DBTestConfiguration() + + const migrationFunction = jest.fn() + + const MIGRATIONS = [ + { + type: MigrationType.GLOBAL, + name: "test" as any, + fn: migrationFunction, + }, + ] + + beforeEach(() => { + config.newTenant() + }) + + afterEach(async () => { + jest.clearAllMocks() + }) + + const migrate = () => { + return migrations.runMigrations(MIGRATIONS, { + tenantIds: [config.tenantId], + }) + } + + it("should run a new migration", async () => { + await config.doInTenant(async () => { + await migrate() + expect(migrationFunction).toHaveBeenCalled() + const db = context.getGlobalDB() + const doc = await migrations.getMigrationsDoc(db) + expect(doc.test).toBeDefined() + }) + }) + + it("should match snapshot", async () => { + await config.doInTenant(async () => { + await migrate() + const doc = await migrations.getMigrationsDoc(context.getGlobalDB()) + expect(doc).toMatchSnapshot() + }) + }) + + it("should skip a previously run migration", async () => { + await config.doInTenant(async () => { + const db = context.getGlobalDB() + await migrate() + const previousDoc = await migrations.getMigrationsDoc(db) + await migrate() + const currentDoc = await migrations.getMigrationsDoc(db) + expect(migrationFunction).toHaveBeenCalledTimes(1) + expect(currentDoc.test).toBe(previousDoc.test) + }) + }) +}) diff --git a/packages/backend-core/src/redis/init.ts b/packages/backend-core/src/redis/init.ts index 00329ffb84..485268edad 100644 --- a/packages/backend-core/src/redis/init.ts +++ b/packages/backend-core/src/redis/init.ts @@ -20,13 +20,17 @@ async function init() { ).init() } -process.on("exit", async () => { +export async function shutdown() { if (userClient) await userClient.finish() if (sessionClient) await sessionClient.finish() if (appClient) await appClient.finish() if (cacheClient) await cacheClient.finish() if (writethroughClient) await writethroughClient.finish() if (lockClient) await lockClient.finish() +} + +process.on("exit", async () => { + await shutdown() }) export async function getUserClient() { diff --git a/packages/backend-core/src/redis/redis.ts b/packages/backend-core/src/redis/redis.ts index 2669cd816a..951369496a 100644 --- a/packages/backend-core/src/redis/redis.ts +++ b/packages/backend-core/src/redis/redis.ts @@ -91,6 +91,11 @@ function init(selectDb = DEFAULT_SELECT_DB) { } // attach handlers client.on("end", (err: Error) => { + if (env.isTest()) { + // don't try to re-connect in test env + // allow the process to exit + return + } connectionError(selectDb, timeout, err) }) client.on("error", (err: Error) => { diff --git a/packages/backend-core/tests/utilities/DBTestConfiguration.ts b/packages/backend-core/tests/utilities/DBTestConfiguration.ts index cad62e2979..e5e57a99a3 100644 --- a/packages/backend-core/tests/utilities/DBTestConfiguration.ts +++ b/packages/backend-core/tests/utilities/DBTestConfiguration.ts @@ -12,6 +12,10 @@ class DBTestConfiguration { this.tenantId = structures.tenant.id() } + newTenant() { + this.tenantId = structures.tenant.id() + } + // TENANCY doInTenant(task: any) { diff --git a/packages/server/jest.config.ts b/packages/server/jest.config.ts index 41558d4c8e..331912aa19 100644 --- a/packages/server/jest.config.ts +++ b/packages/server/jest.config.ts @@ -11,22 +11,17 @@ const baseConfig: Config.InitialProjectOptions = { transform: { "^.+\\.ts?$": "@swc/jest", }, -} - -if (!process.env.CI) { - // use sources when not in CI - baseConfig.moduleNameMapper = { + moduleNameMapper: { "@budibase/backend-core/(.*)": "/../backend-core/$1", "@budibase/backend-core": "/../backend-core/src", "@budibase/types": "/../types/src", - } - // add pro sources if they exist - if (fs.existsSync("../../../budibase-pro")) { - baseConfig.moduleNameMapper["@budibase/pro"] = - "/../../../budibase-pro/packages/pro/src" - } -} else { - console.log("Running tests with compiled dependency sources") + }, +} + +// add pro sources if they exist +if (fs.existsSync("../../../budibase-pro")) { + baseConfig.moduleNameMapper["@budibase/pro"] = + "/../../../budibase-pro/packages/pro/src" } const config: Config.InitialOptions = { diff --git a/packages/server/package.json b/packages/server/package.json index 5812a84717..3eb133e272 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -14,7 +14,7 @@ "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", "debug": "yarn build && node --expose-gc --inspect=9222 dist/index.js", "postbuild": "copyfiles -u 1 src/**/*.svelte dist/ && copyfiles -u 1 src/**/*.hbs dist/ && copyfiles -u 1 src/**/*.json dist/", - "test": "jest --coverage --maxWorkers=2", + "test": "jest --coverage --runInBand", "test:watch": "jest --watch", "predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client", "build:docker": "yarn run predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION", diff --git a/packages/server/specs/resources/query.js b/packages/server/specs/resources/query.js index 10544ee7eb..1442e46a04 100644 --- a/packages/server/specs/resources/query.js +++ b/packages/server/specs/resources/query.js @@ -1,6 +1,6 @@ const Resource = require("./utils/Resource") const { object } = require("./utils") -const { BaseQueryVerbs } = require("../../dist/constants") +const { BaseQueryVerbs } = require("../../src/constants") const query = { _id: "query_datasource_plus_4d8be0c506b9465daf4bf84d890fdab6_454854487c574d45bc4029b1e153219e", diff --git a/packages/server/specs/resources/table.js b/packages/server/specs/resources/table.js index 9bc57daf42..523a3a9dfd 100644 --- a/packages/server/specs/resources/table.js +++ b/packages/server/specs/resources/table.js @@ -2,7 +2,7 @@ const { FieldTypes, RelationshipTypes, FormulaTypes, -} = require("../../dist/constants") +} = require("../../src/constants") const { object } = require("./utils") const Resource = require("./utils/Resource") diff --git a/packages/server/src/api/routes/tests/static.spec.js b/packages/server/src/api/routes/tests/static.spec.js index a0532f12fb..13d963d057 100644 --- a/packages/server/src/api/routes/tests/static.spec.js +++ b/packages/server/src/api/routes/tests/static.spec.js @@ -13,18 +13,6 @@ describe("/static", () => { app = await config.init() }) - describe("/builder", () => { - it("should serve the builder", async () => { - const res = await request - .get("/builder/portal") - .set(config.defaultHeaders()) - .expect("Content-Type", /text\/html/) - .expect(200) - - expect(res.text).toContain("Budibase") - }) - }) - describe("/app", () => { beforeEach(() => { jest.clearAllMocks() diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index bae784cf3d..6b674a8479 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -1,4 +1,4 @@ -const { roles, utils } = require("@budibase/backend-core") +const { roles } = require("@budibase/backend-core") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const setup = require("./utilities") const { BUILTIN_ROLE_IDS } = roles @@ -21,8 +21,7 @@ describe("/users", () => { afterAll(setup.afterAll) - // For some reason this cannot be a beforeAll or the test "should be able to update the user" fail - beforeEach(async () => { + beforeAll(async () => { await config.init() }) diff --git a/packages/server/src/utilities/redis.ts b/packages/server/src/utilities/redis.ts index 1b7a3ce64c..dc37baae58 100644 --- a/packages/server/src/utilities/redis.ts +++ b/packages/server/src/utilities/redis.ts @@ -21,6 +21,8 @@ export async function shutdown() { if (devAppClient) await devAppClient.finish() if (debounceClient) await debounceClient.finish() if (flagClient) await flagClient.finish() + // shutdown core clients + await redis.clients.shutdown() console.log("Redis shutdown") } diff --git a/packages/worker/jest.config.ts b/packages/worker/jest.config.ts index 8b0514211b..cdacfa411a 100644 --- a/packages/worker/jest.config.ts +++ b/packages/worker/jest.config.ts @@ -12,24 +12,19 @@ const config: Config.InitialOptions = { transform: { "^.+\\.ts?$": "@swc/jest", }, -} - -if (!process.env.CI) { - // use sources when not in CI - config.moduleNameMapper = { + moduleNameMapper: { "@budibase/backend-core/(.*)": "/../backend-core/$1", "@budibase/backend-core": "/../backend-core/src", "@budibase/types": "/../types/src", - } - // add pro sources if they exist - if (fs.existsSync("../../../budibase-pro")) { - config.moduleNameMapper["@budibase/pro/(.*)"] = - "/../../../budibase-pro/packages/pro/$1" - config.moduleNameMapper["@budibase/pro"] = - "/../../../budibase-pro/packages/pro/src" - } -} else { - console.log("Running tests with compiled dependency sources") + }, +} + +// add pro sources if they exist +if (fs.existsSync("../../../budibase-pro")) { + config.moduleNameMapper["@budibase/pro/(.*)"] = + "/../../../budibase-pro/packages/pro/$1" + config.moduleNameMapper["@budibase/pro"] = + "/../../../budibase-pro/packages/pro/src" } export default config diff --git a/packages/worker/package.json b/packages/worker/package.json index 9fd2843ae4..0fb3abe53b 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -22,7 +22,7 @@ "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", "dev:builder": "npm run dev:stack:init && nodemon", - "test": "jest --coverage --maxWorkers=2", + "test": "jest --coverage --runInBand", "test:watch": "jest --watch", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", diff --git a/packages/worker/src/utilities/redis.ts b/packages/worker/src/utilities/redis.ts index 893ec9f0a8..9171fe97ee 100644 --- a/packages/worker/src/utilities/redis.ts +++ b/packages/worker/src/utilities/redis.ts @@ -54,6 +54,8 @@ export async function init() { export async function shutdown() { if (pwResetClient) await pwResetClient.finish() if (invitationClient) await invitationClient.finish() + // shutdown core clients + await redis.clients.shutdown() console.log("Redis shutdown") } From 41eb0c3964727861937f36ac30930547c76031f9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 17:22:23 +0000 Subject: [PATCH 079/273] Updating worker db config to have replication available (for audit logs). --- packages/server/src/db/index.ts | 4 ++-- packages/worker/src/db/index.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/server/src/db/index.ts b/packages/server/src/db/index.ts index fa8027dcc1..157c2f4fb3 100644 --- a/packages/server/src/db/index.ts +++ b/packages/server/src/db/index.ts @@ -1,4 +1,4 @@ -import { init as coreInit } from "@budibase/backend-core" +import * as core from "@budibase/backend-core" import env from "../environment" export function init() { @@ -12,5 +12,5 @@ export function init() { dbConfig.allDbs = true } - coreInit({ db: dbConfig }) + core.init({ db: dbConfig }) } diff --git a/packages/worker/src/db/index.ts b/packages/worker/src/db/index.ts index d74d00d910..157c2f4fb3 100644 --- a/packages/worker/src/db/index.ts +++ b/packages/worker/src/db/index.ts @@ -1,10 +1,16 @@ import * as core from "@budibase/backend-core" import env from "../environment" -export const init = () => { - const dbConfig: any = {} +export function init() { + const dbConfig: any = { + replication: true, + find: true, + } + if (env.isTest() && !env.COUCH_DB_URL) { dbConfig.inMemory = true + dbConfig.allDbs = true } + core.init({ db: dbConfig }) } From deb76ca7f38ffccebc0d8c7a343f9cbcb7247f1e Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 17:33:47 +0000 Subject: [PATCH 080/273] v2.3.18-alpha.1 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index a881722de6..64c2e16b71 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index a32f5fd4dd..a5603730de 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.0", + "@budibase/types": "2.3.18-alpha.1", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 9e3aea5fea..d45ce99270 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "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.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.1", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index f8f6ac289d..b8b9c2e79c 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.0", - "@budibase/client": "2.3.18-alpha.0", - "@budibase/frontend-core": "2.3.18-alpha.0", - "@budibase/string-templates": "2.3.18-alpha.0", + "@budibase/bbui": "2.3.18-alpha.1", + "@budibase/client": "2.3.18-alpha.1", + "@budibase/frontend-core": "2.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.1", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index f2044f9c8b..1b675c1f37 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "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.3.18-alpha.0", - "@budibase/string-templates": "2.3.18-alpha.0", - "@budibase/types": "2.3.18-alpha.0", + "@budibase/backend-core": "2.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.1", + "@budibase/types": "2.3.18-alpha.1", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index a784cfa6bc..b3f8734aff 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "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.3.18-alpha.0", - "@budibase/frontend-core": "2.3.18-alpha.0", - "@budibase/string-templates": "2.3.18-alpha.0", + "@budibase/bbui": "2.3.18-alpha.1", + "@budibase/frontend-core": "2.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.1", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index b0d39ed450..1753a0ecbd 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.0", + "@budibase/bbui": "2.3.18-alpha.1", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 597c3dff84..8b58c801fb 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 3eb133e272..d88c41f056 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "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.3.18-alpha.0", - "@budibase/client": "2.3.18-alpha.0", + "@budibase/backend-core": "2.3.18-alpha.1", + "@budibase/client": "2.3.18-alpha.1", "@budibase/pro": "2.3.18-alpha.0", - "@budibase/string-templates": "2.3.18-alpha.0", - "@budibase/types": "2.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.1", + "@budibase/types": "2.3.18-alpha.1", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index edae9518ca..c2e06902e2 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 3153bad674..d378335af8 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 0fb3abe53b..b2c7d93f94 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.0", + "version": "2.3.18-alpha.1", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.0", + "@budibase/backend-core": "2.3.18-alpha.1", "@budibase/pro": "2.3.18-alpha.0", - "@budibase/string-templates": "2.3.18-alpha.0", - "@budibase/types": "2.3.18-alpha.0", + "@budibase/string-templates": "2.3.18-alpha.1", + "@budibase/types": "2.3.18-alpha.1", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 1e0e3ce19ef74e7f62afd78c0986e7ade013d38a Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 21 Feb 2023 17:37:00 +0000 Subject: [PATCH 081/273] Update pro version to 2.3.18-alpha.1 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index d88c41f056..c8c48044ab 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.1", "@budibase/client": "2.3.18-alpha.1", - "@budibase/pro": "2.3.18-alpha.0", + "@budibase/pro": "2.3.18-alpha.1", "@budibase/string-templates": "2.3.18-alpha.1", "@budibase/types": "2.3.18-alpha.1", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 4d31641d3f..125ca007dd 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.0.tgz#c0a64a150c1fef9cc69f95f0aece4e857d64438d" - integrity sha512-ugD+WMoFwpXm+moSLHUgaBOu4XpX0+5UhmMWcNeRtH0Yd9GpDh2QzwtoN8BtXq8k5gkVEyoNSz+6oxKfNkNVdQ== +"@budibase/backend-core@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.1.tgz#af5110dd16dd6a1bf378e4fadd312f920afadd3e" + integrity sha512-p5oNTWYjHMj2HdKrAP2vrVWCiU8tTQ978jgyvwgtBC8TfElowHN5Ly7HLu67v8IeSGK9BGZ7sz6kcS6ApcZa8Q== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.0" + "@budibase/types" "2.3.18-alpha.1" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.0.tgz#e87a2449d9e2453766c0ea77539af359bf5a81ff" - integrity sha512-nKLhCdLxmBX+VY7LF6daH0/AItcHoQTmBB3tc0SP7y4OLcJZfBEYidoWqWJKCgdz6LScWWogLgbDIAC8t+LNzg== +"@budibase/pro@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.1.tgz#de1b7b271102fc3c62138dfdd130bf9af9f4c53f" + integrity sha512-mqyqsE0jg0kBbNrACti69iMfaVO/GgfHYsRizrN9xMwNRUamiwYROLvWYWouyCJYJAkTCTjll6Wex8CpinllCA== dependencies: - "@budibase/backend-core" "2.3.18-alpha.0" - "@budibase/types" "2.3.18-alpha.0" + "@budibase/backend-core" "2.3.18-alpha.1" + "@budibase/types" "2.3.18-alpha.1" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.0.tgz#14480e760c9e7931e884e9e0f8b1d5dd7e5d91c9" - integrity sha512-d+OcW2sNYw7VthMGrOBRY2Bz6iPQVWOnJ94XfYlBRJVIoYwBgudbYkOXPz/vQmHyjSUQFobrvs6UDeZ/3VJTaA== +"@budibase/types@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.1.tgz#d917e512d8644d94d71d0c8cb0d2e9cacecee720" + integrity sha512-35cX1NJfDwRb8DX3RkWVx46yT9+0fMndWSpOX+183ps0BTMyQ0UJBb80pNSsKMGjlgE+loQEXf0LymZ6vr9ucQ== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index b2c7d93f94..90c7a2773d 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.1", - "@budibase/pro": "2.3.18-alpha.0", + "@budibase/pro": "2.3.18-alpha.1", "@budibase/string-templates": "2.3.18-alpha.1", "@budibase/types": "2.3.18-alpha.1", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 83417a2e84..358d122930 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.0.tgz#c0a64a150c1fef9cc69f95f0aece4e857d64438d" - integrity sha512-ugD+WMoFwpXm+moSLHUgaBOu4XpX0+5UhmMWcNeRtH0Yd9GpDh2QzwtoN8BtXq8k5gkVEyoNSz+6oxKfNkNVdQ== +"@budibase/backend-core@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.1.tgz#af5110dd16dd6a1bf378e4fadd312f920afadd3e" + integrity sha512-p5oNTWYjHMj2HdKrAP2vrVWCiU8tTQ978jgyvwgtBC8TfElowHN5Ly7HLu67v8IeSGK9BGZ7sz6kcS6ApcZa8Q== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.0" + "@budibase/types" "2.3.18-alpha.1" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.0.tgz#e87a2449d9e2453766c0ea77539af359bf5a81ff" - integrity sha512-nKLhCdLxmBX+VY7LF6daH0/AItcHoQTmBB3tc0SP7y4OLcJZfBEYidoWqWJKCgdz6LScWWogLgbDIAC8t+LNzg== +"@budibase/pro@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.1.tgz#de1b7b271102fc3c62138dfdd130bf9af9f4c53f" + integrity sha512-mqyqsE0jg0kBbNrACti69iMfaVO/GgfHYsRizrN9xMwNRUamiwYROLvWYWouyCJYJAkTCTjll6Wex8CpinllCA== dependencies: - "@budibase/backend-core" "2.3.18-alpha.0" - "@budibase/types" "2.3.18-alpha.0" + "@budibase/backend-core" "2.3.18-alpha.1" + "@budibase/types" "2.3.18-alpha.1" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.0": - version "2.3.18-alpha.0" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.0.tgz#14480e760c9e7931e884e9e0f8b1d5dd7e5d91c9" - integrity sha512-d+OcW2sNYw7VthMGrOBRY2Bz6iPQVWOnJ94XfYlBRJVIoYwBgudbYkOXPz/vQmHyjSUQFobrvs6UDeZ/3VJTaA== +"@budibase/types@2.3.18-alpha.1": + version "2.3.18-alpha.1" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.1.tgz#d917e512d8644d94d71d0c8cb0d2e9cacecee720" + integrity sha512-35cX1NJfDwRb8DX3RkWVx46yT9+0fMndWSpOX+183ps0BTMyQ0UJBb80pNSsKMGjlgE+loQEXf0LymZ6vr9ucQ== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 22f42ef898ce57b42cf6ac158cfb748fbc0d445c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 21 Feb 2023 19:14:57 +0000 Subject: [PATCH 082/273] Adding new mechanism to get the ipAddress and userAgent of call for audit logs. --- packages/backend-core/src/context/identity.ts | 13 ++++- packages/backend-core/src/events/events.ts | 52 +++++++++++++++---- .../backend-core/src/events/identification.ts | 1 + .../src/middleware/authenticated.ts | 6 +-- packages/backend-core/src/queue/constants.ts | 1 + packages/frontend-core/src/api/auditLogs.js | 6 +-- packages/server/package.json | 1 + packages/server/src/app.ts | 2 + packages/server/yarn.lock | 12 +++++ packages/types/src/sdk/auditLogs.ts | 3 +- packages/types/src/sdk/context.ts | 3 +- .../types/src/sdk/events/identification.ts | 6 +++ packages/worker/package.json | 1 + .../worker/src/api/controllers/global/auth.ts | 6 +-- packages/worker/src/index.ts | 3 ++ packages/worker/yarn.lock | 12 +++++ 16 files changed, 104 insertions(+), 24 deletions(-) diff --git a/packages/backend-core/src/context/identity.ts b/packages/backend-core/src/context/identity.ts index 648dd1b5fd..84de3b68c9 100644 --- a/packages/backend-core/src/context/identity.ts +++ b/packages/backend-core/src/context/identity.ts @@ -5,6 +5,8 @@ import { isCloudAccount, Account, AccountUserContext, + UserContext, + Ctx, } from "@budibase/types" import * as context from "." @@ -16,15 +18,22 @@ export function doInIdentityContext(identity: IdentityContext, task: any) { return context.doInIdentityContext(identity, task) } -export function doInUserContext(user: User, task: any) { - const userContext: any = { +// used in server/worker +export function doInUserContext(user: User, ctx: Ctx, task: any) { + const userContext: UserContext = { ...user, _id: user._id as string, type: IdentityType.USER, + hostInfo: { + ipAddress: ctx.request.ip, + // filled in by koa-useragent package + userAgent: ctx.userAgent._agent.source, + }, } return doInIdentityContext(userContext, task) } +// used in account portal export function doInAccountContext(account: Account, task: any) { const _id = getAccountUserId(account) const tenantId = account.tenantId diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index ba4b0a7448..6176fb6724 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,13 +1,37 @@ -import { Event, IdentityType, AuditLogFn } from "@budibase/types" +import { AuditLogFn, Event, IdentityType, HostInfo } from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" import * as backfill from "./backfill" +import { createQueue, JobQueue } from "../queue" +import BullQueue from "bull" -let writeAuditLogs: AuditLogFn | undefined +type AuditLogEvent = { + event: Event + properties: any + opts: { + timestamp?: string | number + userId?: string + appId?: string + hostInfo?: HostInfo + } +} + +let auditLogsEnabled = false +let auditLogQueue: BullQueue.Queue export const configure = (fn: AuditLogFn) => { - writeAuditLogs = fn + auditLogsEnabled = true + const writeAuditLogs = fn + auditLogQueue = createQueue(JobQueue.AUDIT_LOG) + return auditLogQueue.process(async job => { + await writeAuditLogs(job.data.event, job.data.properties, { + userId: job.data.opts.userId, + timestamp: job.data.opts.timestamp, + appId: job.data.opts.appId, + hostInfo: job.data.opts.hostInfo, + }) + }) } export const publishEvent = async ( @@ -21,16 +45,22 @@ export const publishEvent = async ( const backfilling = await backfill.isBackfillingEvent(event) // no backfill - send the event and exit if (!backfilling) { - // only audit log actual events, don't include backfills - const userId = identity.type === IdentityType.USER ? identity.id : undefined - if (writeAuditLogs) { - await writeAuditLogs(event, properties, { - userId, - timestamp, - appId: getAppId(), + await processors.processEvent(event, identity, properties, timestamp) + if (auditLogsEnabled) { + // only audit log actual events, don't include backfills + const userId = + identity.type === IdentityType.USER ? identity.id : undefined + // add to event queue, rather than just writing immediately + await auditLogQueue.add({ + event, + properties, + opts: { + userId, + timestamp, + appId: getAppId(), + }, }) } - await processors.processEvent(event, identity, properties, timestamp) return } diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts index 7cade9e14b..e18d96bbe0 100644 --- a/packages/backend-core/src/events/identification.ts +++ b/packages/backend-core/src/events/identification.ts @@ -89,6 +89,7 @@ const getCurrentIdentity = async (): Promise => { installationId, tenantId, environment, + hostInfo: userContext.host, } } else { throw new Error("Unknown identity type") diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index 4bb2aaba76..cce27823c0 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -8,7 +8,7 @@ import { getGlobalDB, doInTenant } from "../context" import { decrypt } from "../security/encryption" import * as identity from "../context/identity" import env from "../environment" -import { BBContext, EndpointMatcher } from "@budibase/types" +import { Ctx, EndpointMatcher } from "@budibase/types" const ONE_MINUTE = env.SESSION_UPDATE_PERIOD ? parseInt(env.SESSION_UPDATE_PERIOD) @@ -73,7 +73,7 @@ export default function ( } ) { const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : [] - return async (ctx: BBContext | any, next: any) => { + return async (ctx: Ctx | any, next: any) => { let publicEndpoint = false const version = ctx.request.headers[Header.API_VER] // the path is not authenticated @@ -148,7 +148,7 @@ export default function ( finalise(ctx, { authenticated, user, internal, version, publicEndpoint }) if (user && user.email) { - return identity.doInUserContext(user, next) + return identity.doInUserContext(user, ctx, next) } else { return next() } diff --git a/packages/backend-core/src/queue/constants.ts b/packages/backend-core/src/queue/constants.ts index e8323dacb8..9261ed1176 100644 --- a/packages/backend-core/src/queue/constants.ts +++ b/packages/backend-core/src/queue/constants.ts @@ -1,4 +1,5 @@ export enum JobQueue { AUTOMATION = "automationQueue", APP_BACKUP = "appBackupQueue", + AUDIT_LOG = "auditLogQueue", } diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 745bfbc742..ee8f1b5520 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -18,15 +18,15 @@ const buildOpts = ({ } if (events) { - opts.event = events + opts.events = events } if (userIds) { - opts.userId = userIds + opts.userIds = userIds } if (appIds) { - opts.appId = appIds + opts.appIds = appIds } return opts diff --git a/packages/server/package.json b/packages/server/package.json index 3eb133e272..98b69d4b61 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -87,6 +87,7 @@ "koa-send": "5.0.0", "koa-session": "5.12.0", "koa-static": "5.0.0", + "koa-useragent": "^4.1.0", "koa2-ratelimit": "1.1.1", "lodash": "4.17.21", "memorystream": "0.3.1", diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 6779b35457..86b2783533 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -33,6 +33,7 @@ import { initialise as initialiseWebsockets } from "./websocket" import { startup } from "./startup" const Sentry = require("@sentry/node") const destroyable = require("server-destroy") +const { userAgent } = require("koa-useragent") // configure events to use the pro audit log write // can't integrate directly into backend-core due to cyclic issues @@ -58,6 +59,7 @@ app.use( ) app.use(middleware.logging) +app.use(userAgent) if (env.isProd()) { env._set("NODE_ENV", "production") diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index eb0a7c4def..383c3f1bff 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -6976,6 +6976,11 @@ expose-loader@^3.1.0: resolved "https://registry.yarnpkg.com/expose-loader/-/expose-loader-3.1.0.tgz#7a0bdecb345b921ca238a8c4715a4ea7e227213f" integrity sha512-2RExSo0yJiqP+xiUue13jQa2IHE8kLDzTI7b6kn+vUlBVvlzNSiLDzo4e5Pp5J039usvTUnxZ8sUOhv0Kg15NA== +express-useragent@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.15.tgz#cefda5fa4904345d51d3368b117a8dd4124985d9" + integrity sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg== + ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -10236,6 +10241,13 @@ koa-static@5.0.0, koa-static@^5.0.0: debug "^3.1.0" koa-send "^5.0.0" +koa-useragent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468" + integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA== + dependencies: + express-useragent "^1.0.15" + koa-views@^7.0.1: version "7.0.2" resolved "https://registry.yarnpkg.com/koa-views/-/koa-views-7.0.2.tgz#c96fd9e2143ef00c29dc5160c5ed639891aa723d" diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts index 9f8eb3825c..dea36b0164 100644 --- a/packages/types/src/sdk/auditLogs.ts +++ b/packages/types/src/sdk/auditLogs.ts @@ -1,9 +1,10 @@ -import { Event } from "./events" +import { Event, HostInfo } from "./events" export type AuditWriteOpts = { appId?: string timestamp?: string | number userId?: string + hostInfo?: HostInfo } export type AuditLogFn = ( diff --git a/packages/types/src/sdk/context.ts b/packages/types/src/sdk/context.ts index b3403df8af..c8345de196 100644 --- a/packages/types/src/sdk/context.ts +++ b/packages/types/src/sdk/context.ts @@ -1,5 +1,5 @@ import { User, Account } from "../documents" -import { IdentityType } from "./events" +import { IdentityType, HostInfo } from "./events" export interface BaseContext { _id: string @@ -16,6 +16,7 @@ export interface UserContext extends BaseContext, User { _id: string tenantId: string account?: Account + hostInfo: HostInfo } export type IdentityContext = BaseContext | AccountUserContext | UserContext diff --git a/packages/types/src/sdk/events/identification.ts b/packages/types/src/sdk/events/identification.ts index 3f4e7ec9d4..bbbf74d33e 100644 --- a/packages/types/src/sdk/events/identification.ts +++ b/packages/types/src/sdk/events/identification.ts @@ -34,6 +34,11 @@ export enum IdentityType { INSTALLATION = "installation", } +export interface HostInfo { + ipAddress: string + userAgent: string +} + export interface Identity { id: string type: IdentityType @@ -41,6 +46,7 @@ export interface Identity { environment: string installationId?: string tenantId?: string + hostInfo: HostInfo } export interface UserIdentity extends Identity { diff --git a/packages/worker/package.json b/packages/worker/package.json index 0fb3abe53b..c1912054c4 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -60,6 +60,7 @@ "koa-send": "5.0.1", "koa-session": "5.13.1", "koa-static": "5.0.0", + "koa-useragent": "^4.1.0", "node-fetch": "2.6.7", "nodemailer": "6.7.2", "passport-google-oauth": "2.0.0", diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index 1e55d4de0d..318f69c7ad 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -69,7 +69,7 @@ export const login = async (ctx: Ctx, next: any) => { "local", async (err: any, user: User, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("local", user.email) }) ctx.status = 200 @@ -211,7 +211,7 @@ export const googleCallback = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: SSOUser, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("google-internal", user.email) }) ctx.redirect("/") @@ -281,7 +281,7 @@ export const oidcCallback = async (ctx: any, next: any) => { { successRedirect: "/", failureRedirect: "/error" }, async (err: any, user: SSOUser, info: any) => { await passportCallback(ctx, user, err, info) - await context.identity.doInUserContext(user, async () => { + await context.identity.doInUserContext(user, ctx, async () => { await events.auth.login("oidc", user.email) }) ctx.redirect("/") diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 69cd900637..750ae0055d 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -24,6 +24,8 @@ import * as redis from "./utilities/redis" const Sentry = require("@sentry/node") const koaSession = require("koa-session") const logger = require("koa-pino-logger") +const { userAgent } = require("koa-useragent") + import destroyable from "server-destroy" // configure events to use the pro audit log write @@ -48,6 +50,7 @@ app.use(koaBody({ multipart: true })) app.use(koaSession(app)) app.use(middleware.logging) app.use(logger(logging.pinoSettings())) +app.use(userAgent) // authentication app.use(auth.passport.initialize()) diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 83417a2e84..35af60204e 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -3653,6 +3653,11 @@ expect@^28.1.3: jest-message-util "^28.1.3" jest-util "^28.1.3" +express-useragent@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/express-useragent/-/express-useragent-1.0.15.tgz#cefda5fa4904345d51d3368b117a8dd4124985d9" + integrity sha512-eq5xMiYCYwFPoekffMjvEIk+NWdlQY9Y38OsTyl13IvA728vKT+q/CSERYWzcw93HGBJcIqMIsZC5CZGARPVdg== + extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -5467,6 +5472,13 @@ koa-static@5.0.0: debug "^3.1.0" koa-send "^5.0.0" +koa-useragent@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-useragent/-/koa-useragent-4.1.0.tgz#d3f128b552c6da3e5e9e9e9c887b2922b16e4468" + integrity sha512-x/HUDZ1zAmNNh5hA9hHbPm9p3UVg2prlpHzxCXQCzbibrNS0kmj7MkCResCbAbG7ZT6FVxNSMjR94ZGamdMwxA== + dependencies: + express-useragent "^1.0.15" + koa@2.13.4, koa@^2.13.4: version "2.13.4" resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e" From 6a88cfc32db9b4211d96e4450ea7b21529794c55 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 22 Feb 2023 08:32:03 +0000 Subject: [PATCH 083/273] Update locks error logging (#9768) * Fix intermittent backend-core migration test failure * Update lock logging --- packages/backend-core/src/redis/redlock.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/backend-core/src/redis/redlock.ts b/packages/backend-core/src/redis/redlock.ts index 2021da2b56..136d7f5d33 100644 --- a/packages/backend-core/src/redis/redlock.ts +++ b/packages/backend-core/src/redis/redlock.ts @@ -85,17 +85,20 @@ export const doWithLock = async (opts: LockOptions, task: any) => { const result = await task() return result } catch (e: any) { - console.log("lock error") + console.warn("lock error") // lock limit exceeded if (e.name === "LockError") { if (opts.type === LockType.TRY_ONCE) { // don't throw for try-once locks, they will always error // due to retry count (0) exceeded + console.warn(e) return } else { + console.error(e) throw e } } else { + console.error(e) throw e } } finally { From 288f853208f748b4a80d59f65c1e45c85e1146ab Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 08:40:11 +0000 Subject: [PATCH 084/273] v2.3.18-alpha.2 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 64c2e16b71..fe2aecb942 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index a5603730de..03bf98ed05 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.1", + "@budibase/types": "2.3.18-alpha.2", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index d45ce99270..f223d0fecd 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "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.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.2", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index b8b9c2e79c..f6252a4928 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.1", - "@budibase/client": "2.3.18-alpha.1", - "@budibase/frontend-core": "2.3.18-alpha.1", - "@budibase/string-templates": "2.3.18-alpha.1", + "@budibase/bbui": "2.3.18-alpha.2", + "@budibase/client": "2.3.18-alpha.2", + "@budibase/frontend-core": "2.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.2", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 1b675c1f37..0595259f56 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "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.3.18-alpha.1", - "@budibase/string-templates": "2.3.18-alpha.1", - "@budibase/types": "2.3.18-alpha.1", + "@budibase/backend-core": "2.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.2", + "@budibase/types": "2.3.18-alpha.2", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index b3f8734aff..7154228c2c 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "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.3.18-alpha.1", - "@budibase/frontend-core": "2.3.18-alpha.1", - "@budibase/string-templates": "2.3.18-alpha.1", + "@budibase/bbui": "2.3.18-alpha.2", + "@budibase/frontend-core": "2.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.2", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 1753a0ecbd..30a202dd19 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.1", + "@budibase/bbui": "2.3.18-alpha.2", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 8b58c801fb..a20fd61d9b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index c8c48044ab..caf3d09f76 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "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.3.18-alpha.1", - "@budibase/client": "2.3.18-alpha.1", + "@budibase/backend-core": "2.3.18-alpha.2", + "@budibase/client": "2.3.18-alpha.2", "@budibase/pro": "2.3.18-alpha.1", - "@budibase/string-templates": "2.3.18-alpha.1", - "@budibase/types": "2.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.2", + "@budibase/types": "2.3.18-alpha.2", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index c2e06902e2..810eff7712 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index d378335af8..a5cfd06cbd 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 90c7a2773d..fdd5edcfc5 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.1", + "version": "2.3.18-alpha.2", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.1", + "@budibase/backend-core": "2.3.18-alpha.2", "@budibase/pro": "2.3.18-alpha.1", - "@budibase/string-templates": "2.3.18-alpha.1", - "@budibase/types": "2.3.18-alpha.1", + "@budibase/string-templates": "2.3.18-alpha.2", + "@budibase/types": "2.3.18-alpha.2", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From faaf01cd5355f09ce7141592d33a15d82e2a9935 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 08:43:41 +0000 Subject: [PATCH 085/273] Update pro version to 2.3.18-alpha.2 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index caf3d09f76..e550a9ca38 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.2", "@budibase/client": "2.3.18-alpha.2", - "@budibase/pro": "2.3.18-alpha.1", + "@budibase/pro": "2.3.18-alpha.2", "@budibase/string-templates": "2.3.18-alpha.2", "@budibase/types": "2.3.18-alpha.2", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 125ca007dd..67db7d2d28 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.1.tgz#af5110dd16dd6a1bf378e4fadd312f920afadd3e" - integrity sha512-p5oNTWYjHMj2HdKrAP2vrVWCiU8tTQ978jgyvwgtBC8TfElowHN5Ly7HLu67v8IeSGK9BGZ7sz6kcS6ApcZa8Q== +"@budibase/backend-core@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.2.tgz#a18b075234d184961b03ca89c7ae4b8229cbf279" + integrity sha512-rWI/GGphASPRu3HdPDVPpzbvBBLdFWnD5FyGVJ1/lZ5s0A/npegXl7noaFAgVjrAPGOKWDsDv43sscMzl8ZWLw== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.1" + "@budibase/types" "2.3.18-alpha.2" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.1.tgz#de1b7b271102fc3c62138dfdd130bf9af9f4c53f" - integrity sha512-mqyqsE0jg0kBbNrACti69iMfaVO/GgfHYsRizrN9xMwNRUamiwYROLvWYWouyCJYJAkTCTjll6Wex8CpinllCA== +"@budibase/pro@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.2.tgz#50456af8151b4e2832c3f518ad10e381f2f4e70f" + integrity sha512-x0X4LjFsqgi4OMm+Mlk3NAVHFA3bakVTvOSoKz/7LLa5XN9DaD1AOj7Vwh6iNVuoMmarIS9lj9NlripFzMs1EQ== dependencies: - "@budibase/backend-core" "2.3.18-alpha.1" - "@budibase/types" "2.3.18-alpha.1" + "@budibase/backend-core" "2.3.18-alpha.2" + "@budibase/types" "2.3.18-alpha.2" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.1.tgz#d917e512d8644d94d71d0c8cb0d2e9cacecee720" - integrity sha512-35cX1NJfDwRb8DX3RkWVx46yT9+0fMndWSpOX+183ps0BTMyQ0UJBb80pNSsKMGjlgE+loQEXf0LymZ6vr9ucQ== +"@budibase/types@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.2.tgz#06ac9e16d0aff7eced989cd2133a26cee9d540ee" + integrity sha512-vNSu+E98jmBrQ0hx0Mza2whKScmW5O6mRmvyuJor6R/AhMHYn6k8ChuZsbLmx5C8oRdFT8rquaQxcbENl7I4eA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index fdd5edcfc5..97f4444361 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.2", - "@budibase/pro": "2.3.18-alpha.1", + "@budibase/pro": "2.3.18-alpha.2", "@budibase/string-templates": "2.3.18-alpha.2", "@budibase/types": "2.3.18-alpha.2", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 358d122930..5949e5e5f8 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.1.tgz#af5110dd16dd6a1bf378e4fadd312f920afadd3e" - integrity sha512-p5oNTWYjHMj2HdKrAP2vrVWCiU8tTQ978jgyvwgtBC8TfElowHN5Ly7HLu67v8IeSGK9BGZ7sz6kcS6ApcZa8Q== +"@budibase/backend-core@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.2.tgz#a18b075234d184961b03ca89c7ae4b8229cbf279" + integrity sha512-rWI/GGphASPRu3HdPDVPpzbvBBLdFWnD5FyGVJ1/lZ5s0A/npegXl7noaFAgVjrAPGOKWDsDv43sscMzl8ZWLw== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.1" + "@budibase/types" "2.3.18-alpha.2" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.1.tgz#de1b7b271102fc3c62138dfdd130bf9af9f4c53f" - integrity sha512-mqyqsE0jg0kBbNrACti69iMfaVO/GgfHYsRizrN9xMwNRUamiwYROLvWYWouyCJYJAkTCTjll6Wex8CpinllCA== +"@budibase/pro@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.2.tgz#50456af8151b4e2832c3f518ad10e381f2f4e70f" + integrity sha512-x0X4LjFsqgi4OMm+Mlk3NAVHFA3bakVTvOSoKz/7LLa5XN9DaD1AOj7Vwh6iNVuoMmarIS9lj9NlripFzMs1EQ== dependencies: - "@budibase/backend-core" "2.3.18-alpha.1" - "@budibase/types" "2.3.18-alpha.1" + "@budibase/backend-core" "2.3.18-alpha.2" + "@budibase/types" "2.3.18-alpha.2" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.1": - version "2.3.18-alpha.1" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.1.tgz#d917e512d8644d94d71d0c8cb0d2e9cacecee720" - integrity sha512-35cX1NJfDwRb8DX3RkWVx46yT9+0fMndWSpOX+183ps0BTMyQ0UJBb80pNSsKMGjlgE+loQEXf0LymZ6vr9ucQ== +"@budibase/types@2.3.18-alpha.2": + version "2.3.18-alpha.2" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.2.tgz#06ac9e16d0aff7eced989cd2133a26cee9d540ee" + integrity sha512-vNSu+E98jmBrQ0hx0Mza2whKScmW5O6mRmvyuJor6R/AhMHYn6k8ChuZsbLmx5C8oRdFT8rquaQxcbENl7I4eA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From e7f8a8a8015e2d66a21c92da227b8f114a3019c1 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Wed, 22 Feb 2023 10:03:11 +0000 Subject: [PATCH 086/273] Backups UI Changes (#9726) * Backups UI Changes * PR Feedback --------- Co-authored-by: Rory Powell --- packages/builder/src/helpers/userInitials.js | 13 +++++ .../_components/ActionsRenderer.svelte | 41 ++------------ .../_components/CreateBackupModal.svelte | 22 -------- .../backups/_components/NameRenderer.svelte | 8 --- .../_components/TimeAgoRenderer.svelte | 10 ++++ .../backups/_components/UserRenderer.svelte | 15 ++--- .../overview/[appId]/backups/index.svelte | 55 ++++++++++--------- packages/builder/src/stores/portal/auth.js | 12 +--- packages/builder/src/stores/portal/backups.js | 4 +- packages/frontend-core/src/api/backups.js | 3 +- 10 files changed, 67 insertions(+), 116 deletions(-) create mode 100644 packages/builder/src/helpers/userInitials.js delete mode 100644 packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/CreateBackupModal.svelte delete mode 100644 packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/NameRenderer.svelte create mode 100644 packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte diff --git a/packages/builder/src/helpers/userInitials.js b/packages/builder/src/helpers/userInitials.js new file mode 100644 index 0000000000..c87d38c494 --- /dev/null +++ b/packages/builder/src/helpers/userInitials.js @@ -0,0 +1,13 @@ +const getUserInitials = user => { + if (user.firstName && user.lastName) { + return user.firstName[0] + user.lastName[0] + } else if (user.firstName) { + return user.firstName[0] + } else if (user.email) { + return user.email[0] + } + + return "U" +} + +export default getUserInitials diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte index 7dc302186a..4787112760 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/ActionsRenderer.svelte @@ -3,31 +3,26 @@ ActionMenu, MenuItem, Icon, - Input, Heading, Body, Modal, } from "@budibase/bbui" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import CreateRestoreModal from "./CreateRestoreModal.svelte" - import { createEventDispatcher, onMount } from "svelte" + import { createEventDispatcher } from "svelte" export let row let deleteDialog let restoreDialog - let updateDialog - let name let restoreBackupModal const dispatch = createEventDispatcher() - const onClickRestore = name => { + const onClickRestore = () => { dispatch("buttonclick", { type: "backupRestore", - name, backupId: row._id, - restoreBackupName: name, }) } @@ -38,21 +33,9 @@ }) } - const onClickUpdate = () => { - dispatch("buttonclick", { - type: "backupUpdate", - backupId: row._id, - name, - }) - } - async function downloadExport() { window.open(`/api/apps/${row.appId}/backups/${row._id}/file`, "_blank") } - - onMount(() => { - name = row.name - })
@@ -66,12 +49,11 @@ Delete Download {/if} - Rename
- onClickRestore(name)} /> + - Are you sure you wish to delete the backup - {row.name}? - This action cannot be undone. + Are you sure you wish to delete this backup? This action cannot be undone. - {row.name || "Backup"} + Backup {new Date(row.timestamp).toLocaleString()} - - - - diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/NameRenderer.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/NameRenderer.svelte deleted file mode 100644 index 93eda410fe..0000000000 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/NameRenderer.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - -{truncatedValue} diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte new file mode 100644 index 0000000000..fd67b4010b --- /dev/null +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/TimeAgoRenderer.svelte @@ -0,0 +1,10 @@ + + +{dayjs(value).fromNow()} diff --git a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte index abab314d05..a9aabae857 100644 --- a/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/overview/[appId]/backups/_components/UserRenderer.svelte @@ -1,17 +1,14 @@ -
- {#if value != null} -
{username}
- {/if} +
+
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 821e504774..47c93d23d1 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -9,6 +9,8 @@ clickOutside, CoreTextArea, DatePicker, + Pagination, + Divider, } from "@budibase/bbui" import { licensing, users, apps, auditLogs } from "stores/portal" import LockedFeature from "../../_components/LockedFeature.svelte" @@ -62,16 +64,15 @@ let startDate, endDate $: fetchUsers(userPage, userSearchTerm) - $: fetchLogs( + $: fetchLogs({ logsPage, logSearchTerm, startDate, endDate, selectedUsers, selectedApps, - selectedEvents - ) - + selectedEvents, + }) $: userPage = $userPageInfo.page $: logsPage = $logsPageInfo.page @@ -97,38 +98,38 @@ } } - const fetchLogs = async ( + const fetchLogs = async ({ logsPage, - search, + logSearchTerm, startDate, endDate, selectedUsers, selectedApps, - selectedEvents - ) => { + selectedEvents, + }) => { if ($logsPageInfo.loading) { return } // need to remove the page if they've started searching - if (search && !prevLogSearch) { + if (logSearchTerm && !prevLogSearch) { logsPageInfo.reset() logsPage = undefined } - prevLogSearch = search + prevLogSearch = logSearchTerm try { logsPageInfo.loading() await auditLogs.search({ - logsPage, + bookmark: logsPage, startDate, endDate, - metadataSearch: search, + fullSearch: logSearchTerm, userIds: selectedUsers, appIds: selectedApps, events: selectedEvents, }) logsPageInfo.fetched( $auditLogs.logs.hasNextPage, - $auditLogs.logs.nextPage + $auditLogs.logs.bookmark ) } catch (error) { console.log(error) @@ -161,6 +162,7 @@ } const viewDetails = detail => { + console.log(detail) selectedLog = detail sidePanelVisible = true } @@ -206,9 +208,15 @@ range={true} label="Date Range" on:change={e => { - if (e.detail[0].length > 1) { + console.log(e) + if (e.detail[0]?.length === 1) { + startDate = e.detail[0][0].toISOString() + } else if (e.detail[0]?.length > 1) { startDate = e.detail[0][0].toISOString() endDate = e.detail[0][1].toISOString() + } else { + startDate = null + endDate = null } }} /> @@ -258,14 +266,23 @@
viewDetails(detail)} {customRenderers} - on:click={viewDetails} data={$auditLogs.logs.data} allowEditColumns={false} allowEditRows={false} allowSelectRows={false} {schema} /> + @@ -298,7 +315,9 @@ /> -
+ + +
.side-panel-header { display: flex; + padding: 20px 10px 10px 10px; gap: var(--spacing-s); justify-content: space-between; align-items: center; } + .pagination { + display: flex; + flex-direction: row; + justify-content: flex-end; + margin-top: var(--spacing-xl); + } + + .side-panel-body { + padding: 10px; + height: 95%; + } #side-panel { position: absolute; right: 0; top: 0; - padding: 24px; + padding-bottom: 24px; background: var(--background); border-left: var(--border-light); width: 320px; @@ -330,7 +361,7 @@ overflow-x: hidden; transform: translateX(100%); transition: transform 130ms ease-in-out; - height: calc(100% - 48px); + height: calc(100% - 25px); z-index: 2; } #side-panel.visible { diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js index 3454aab95c..165e4b5ec5 100644 --- a/packages/builder/src/stores/portal/auditLogs.js +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -26,8 +26,6 @@ export function createAuditLogsStore() { update(state => { return { ...state, ...events } }) - - console.log(events) } async function downloadLogs(opts = {}) { diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 745bfbc742..867644c23c 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -1,32 +1,39 @@ const buildOpts = ({ + bookmark, userIds, appIds, startDate, endDate, - metadataSearch, + fullSearch, events, }) => { const opts = {} + if (bookmark) { + opts.bookmark = bookmark + } + if (startDate && endDate) { opts.startDate = startDate opts.endDate = endDate + } else if (startDate && !endDate) { + opts.startDate = startDate } - if (metadataSearch) { - opts.metadataSearch = metadataSearch + if (fullSearch) { + opts.fullSearch = fullSearch } - if (events) { - opts.event = events + if (events.length) { + opts.events = events } - if (userIds) { - opts.userId = userIds + if (userIds.length) { + opts.userIds = userIds } - if (appIds) { - opts.appId = appIds + if (appIds.length) { + opts.appIds = appIds } return opts From a03fe900c654f7a7fe576bb7f7e2227aa434b07b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 10:10:27 +0000 Subject: [PATCH 088/273] v2.3.18-alpha.3 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index fe2aecb942..3e05b82a1e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 03bf98ed05..bc8ec58a7f 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.2", + "@budibase/types": "2.3.18-alpha.3", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index f223d0fecd..c247e32e50 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "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.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.3", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index f6252a4928..ed6fc08ac5 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.2", - "@budibase/client": "2.3.18-alpha.2", - "@budibase/frontend-core": "2.3.18-alpha.2", - "@budibase/string-templates": "2.3.18-alpha.2", + "@budibase/bbui": "2.3.18-alpha.3", + "@budibase/client": "2.3.18-alpha.3", + "@budibase/frontend-core": "2.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.3", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 0595259f56..ce9aa90b8f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "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.3.18-alpha.2", - "@budibase/string-templates": "2.3.18-alpha.2", - "@budibase/types": "2.3.18-alpha.2", + "@budibase/backend-core": "2.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.3", + "@budibase/types": "2.3.18-alpha.3", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 7154228c2c..e0320f52ab 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "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.3.18-alpha.2", - "@budibase/frontend-core": "2.3.18-alpha.2", - "@budibase/string-templates": "2.3.18-alpha.2", + "@budibase/bbui": "2.3.18-alpha.3", + "@budibase/frontend-core": "2.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.3", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 30a202dd19..9a9843af3b 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.2", + "@budibase/bbui": "2.3.18-alpha.3", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index a20fd61d9b..d9d83c7889 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index e550a9ca38..326d231dd1 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "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.3.18-alpha.2", - "@budibase/client": "2.3.18-alpha.2", + "@budibase/backend-core": "2.3.18-alpha.3", + "@budibase/client": "2.3.18-alpha.3", "@budibase/pro": "2.3.18-alpha.2", - "@budibase/string-templates": "2.3.18-alpha.2", - "@budibase/types": "2.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.3", + "@budibase/types": "2.3.18-alpha.3", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 810eff7712..48081eda83 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index a5cfd06cbd..66959cf7c8 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 97f4444361..8be3ffb91e 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.2", + "version": "2.3.18-alpha.3", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.2", + "@budibase/backend-core": "2.3.18-alpha.3", "@budibase/pro": "2.3.18-alpha.2", - "@budibase/string-templates": "2.3.18-alpha.2", - "@budibase/types": "2.3.18-alpha.2", + "@budibase/string-templates": "2.3.18-alpha.3", + "@budibase/types": "2.3.18-alpha.3", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 8e07033ec2e64851d39fa331f3ed1bd362d7c7a4 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 10:13:25 +0000 Subject: [PATCH 089/273] Update pro version to 2.3.18-alpha.3 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 326d231dd1..2eedd09fc9 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.3", "@budibase/client": "2.3.18-alpha.3", - "@budibase/pro": "2.3.18-alpha.2", + "@budibase/pro": "2.3.18-alpha.3", "@budibase/string-templates": "2.3.18-alpha.3", "@budibase/types": "2.3.18-alpha.3", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 67db7d2d28..3f6682875e 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.2.tgz#a18b075234d184961b03ca89c7ae4b8229cbf279" - integrity sha512-rWI/GGphASPRu3HdPDVPpzbvBBLdFWnD5FyGVJ1/lZ5s0A/npegXl7noaFAgVjrAPGOKWDsDv43sscMzl8ZWLw== +"@budibase/backend-core@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.3.tgz#e10f4071cb43a178293b1ad37bcd1d4f45d358a1" + integrity sha512-MbaYwhvV1V9XrJTUP0wBy9fT9FtaJuAi1pOHJNWw3kvUEo7h5AiSp2hOGBoPJwoloeWQfZsJpglSOMA9HJf8fQ== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.2" + "@budibase/types" "2.3.18-alpha.3" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.2.tgz#50456af8151b4e2832c3f518ad10e381f2f4e70f" - integrity sha512-x0X4LjFsqgi4OMm+Mlk3NAVHFA3bakVTvOSoKz/7LLa5XN9DaD1AOj7Vwh6iNVuoMmarIS9lj9NlripFzMs1EQ== +"@budibase/pro@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.3.tgz#73a759ee17600a340c41cb0c4f8d289bf66be66f" + integrity sha512-xNwzB7l5ZvxcqXMZgsaUVvPKufk3mgI/4TBGXB9IpYQRsGFFxrpNMRtQsMfWUEUrXBvFuyr/DPtQJekhrCcMxg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.2" - "@budibase/types" "2.3.18-alpha.2" + "@budibase/backend-core" "2.3.18-alpha.3" + "@budibase/types" "2.3.18-alpha.3" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.2.tgz#06ac9e16d0aff7eced989cd2133a26cee9d540ee" - integrity sha512-vNSu+E98jmBrQ0hx0Mza2whKScmW5O6mRmvyuJor6R/AhMHYn6k8ChuZsbLmx5C8oRdFT8rquaQxcbENl7I4eA== +"@budibase/types@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.3.tgz#a04a46784e833989f4cc7d4c45366a3cefb01f53" + integrity sha512-gkwJdM6zRXulwXQhjSsaDAjJyhbDMVhuFVDcQvS2oZBBrRtBFHfOqLw/dkTC6Zgq9ttu/00B1QihB+uliYRFLQ== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 8be3ffb91e..f28a153247 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.3", - "@budibase/pro": "2.3.18-alpha.2", + "@budibase/pro": "2.3.18-alpha.3", "@budibase/string-templates": "2.3.18-alpha.3", "@budibase/types": "2.3.18-alpha.3", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 5949e5e5f8..123362b958 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.2.tgz#a18b075234d184961b03ca89c7ae4b8229cbf279" - integrity sha512-rWI/GGphASPRu3HdPDVPpzbvBBLdFWnD5FyGVJ1/lZ5s0A/npegXl7noaFAgVjrAPGOKWDsDv43sscMzl8ZWLw== +"@budibase/backend-core@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.3.tgz#e10f4071cb43a178293b1ad37bcd1d4f45d358a1" + integrity sha512-MbaYwhvV1V9XrJTUP0wBy9fT9FtaJuAi1pOHJNWw3kvUEo7h5AiSp2hOGBoPJwoloeWQfZsJpglSOMA9HJf8fQ== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.2" + "@budibase/types" "2.3.18-alpha.3" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.2.tgz#50456af8151b4e2832c3f518ad10e381f2f4e70f" - integrity sha512-x0X4LjFsqgi4OMm+Mlk3NAVHFA3bakVTvOSoKz/7LLa5XN9DaD1AOj7Vwh6iNVuoMmarIS9lj9NlripFzMs1EQ== +"@budibase/pro@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.3.tgz#73a759ee17600a340c41cb0c4f8d289bf66be66f" + integrity sha512-xNwzB7l5ZvxcqXMZgsaUVvPKufk3mgI/4TBGXB9IpYQRsGFFxrpNMRtQsMfWUEUrXBvFuyr/DPtQJekhrCcMxg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.2" - "@budibase/types" "2.3.18-alpha.2" + "@budibase/backend-core" "2.3.18-alpha.3" + "@budibase/types" "2.3.18-alpha.3" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.2": - version "2.3.18-alpha.2" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.2.tgz#06ac9e16d0aff7eced989cd2133a26cee9d540ee" - integrity sha512-vNSu+E98jmBrQ0hx0Mza2whKScmW5O6mRmvyuJor6R/AhMHYn6k8ChuZsbLmx5C8oRdFT8rquaQxcbENl7I4eA== +"@budibase/types@2.3.18-alpha.3": + version "2.3.18-alpha.3" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.3.tgz#a04a46784e833989f4cc7d4c45366a3cefb01f53" + integrity sha512-gkwJdM6zRXulwXQhjSsaDAjJyhbDMVhuFVDcQvS2oZBBrRtBFHfOqLw/dkTC6Zgq9ttu/00B1QihB+uliYRFLQ== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From b9c54b6fe6a2da69a39004851850d967c2f5b299 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 10:54:55 +0000 Subject: [PATCH 090/273] Update many to many --- .../src/api/controllers/row/ExternalRequest.ts | 13 ++++++------- packages/server/src/api/controllers/row/external.ts | 2 +- packages/server/src/integrations/base/sql.ts | 4 +--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index f62e7fe2d0..22a4a90865 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -629,10 +629,7 @@ export class ExternalRequest { * Creating the specific list of fields that we desire, and excluding the ones that are no use to us * is more performant and has the added benefit of protecting against this scenario. */ - buildFields( - table: Table, - includeRelations: IncludeRelationship = IncludeRelationship.INCLUDE - ) { + buildFields(table: Table, includeRelations: boolean) { function extractRealFields(table: Table, existing: string[] = []) { return Object.entries(table.schema) .filter( @@ -691,6 +688,10 @@ export class ExternalRequest { } filters = buildFilters(id, filters || {}, table) const relationships = this.buildRelationships(table) + + const includeSqlRelationships = + config.includeSqlRelationships === IncludeRelationship.INCLUDE + // clean up row on ingress using schema const processed = this.inputProcessing(row, table) row = processed.row @@ -708,9 +709,7 @@ export class ExternalRequest { }, resource: { // have to specify the fields to avoid column overlap (for SQL) - fields: isSql - ? this.buildFields(table, config.includeSqlRelationships) - : [], + fields: isSql ? this.buildFields(table, includeSqlRelationships) : [], }, filters, sort, diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 6120c3cdcb..1b2301f139 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -58,7 +58,7 @@ export async function patch(ctx: BBContext) { return handleRequest(Operation.UPDATE, tableId, { id: breakRowIdField(id), row: inputs, - includeSqlRelationships: IncludeRelationship.EXCLUDE, + includeSqlRelationships: IncludeRelationship.INCLUDE, }) } diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index e66795a6db..c722891910 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -502,9 +502,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.update(parsedBody) } else { - return query - .update(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.update(parsedBody).returning("*") } } From e350f6b166ca69edfd9dfb24e37f7e47e824f812 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 11:02:32 +0000 Subject: [PATCH 091/273] Undo literal changes --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 22a4a90865..56e54e299e 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -316,7 +316,7 @@ export class ExternalRequest { key: otherKey, [thisKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later - [otherKey]: `{{ literal [${table.name}.${tablePrimary}] }}`, + [otherKey]: `{{ literal ${tablePrimary} }}`, }) }) } From ffee41aea320947ae4f50654e3a61b87c82bc202 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 22 Feb 2023 12:31:04 +0000 Subject: [PATCH 092/273] custom popover height and sidebar styling --- .../bbui/src/Form/Core/Multiselect.svelte | 2 + packages/bbui/src/Form/Core/Picker.svelte | 3 + packages/bbui/src/Form/Multiselect.svelte | 2 + packages/bbui/src/Form/Select.svelte | 2 + packages/bbui/src/Popover/Popover.svelte | 2 + .../_components/AppColumnRenderer.svelte | 2 +- .../auditLogs/_components/UserRenderer.svelte | 4 +- .../portal/account/auditLogs/index.svelte | 58 ++++++++++++++++--- 8 files changed, 63 insertions(+), 12 deletions(-) diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index a315f44a65..8860fcbf0b 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -15,6 +15,7 @@ export let sort = false export let autoWidth = false export let fetchTerm = null + export let customPopoverHeight const dispatch = createEventDispatcher() @@ -91,4 +92,5 @@ onSelectOption={toggleOption} {sort} {autoWidth} + {customPopoverHeight} /> diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index ace41aa35b..5cef0f9213 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -32,6 +32,7 @@ export let autocomplete = false export let sort = false export let fetchTerm = null + export let customPopoverHeight const dispatch = createEventDispatcher() let searchTerm = null @@ -136,6 +137,7 @@ on:close={() => (open = false)} useAnchorWidth={!autoWidth} maxWidth={autoWidth ? 400 : null} + customHeight={customPopoverHeight} >
{ @@ -38,6 +39,7 @@ {getOptionValue} {autoWidth} {autocomplete} + {customPopoverHeight} bind:fetchTerm on:change={onChange} on:click diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 4f30318282..76fe613c92 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -21,6 +21,7 @@ export let sort = false export let tooltip = "" export let autocomplete = false + export let customPopoverHeight const dispatch = createEventDispatcher() const onChange = e => { @@ -53,6 +54,7 @@ {getOptionColour} {isOptionEnabled} {autocomplete} + {customPopoverHeight} on:change={onChange} on:click /> diff --git a/packages/bbui/src/Popover/Popover.svelte b/packages/bbui/src/Popover/Popover.svelte index 8f6ef06591..081e3a34df 100644 --- a/packages/bbui/src/Popover/Popover.svelte +++ b/packages/bbui/src/Popover/Popover.svelte @@ -18,6 +18,7 @@ export let useAnchorWidth = false export let dismissible = true export let offset = 5 + export let customHeight $: target = portalTarget || getContext(Context.PopoverRoot) || ".spectrum" @@ -74,6 +75,7 @@ on:keydown={handleEscape} class="spectrum-Popover is-open" role="presentation" + style="height: {customHeight}" transition:fly|local={{ y: -20, duration: 200 }} > diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte index 2ad3997f79..08260ecc5c 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/AppColumnRenderer.svelte @@ -2,4 +2,4 @@ export let value -
{value?.name || "N/A"}
+
{value?.name || ""}
diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte index 5d3d8fa28a..1dfb425965 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/_components/UserRenderer.svelte @@ -18,11 +18,11 @@ on:focus={() => (showTooltip = true)} on:mouseleave={() => (showTooltip = false)} > - +
{#if showTooltip}
- +
{/if} diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 47c93d23d1..4459eb12a5 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -10,6 +10,7 @@ CoreTextArea, DatePicker, Pagination, + Helpers, Divider, } from "@budibase/bbui" import { licensing, users, apps, auditLogs } from "stores/portal" @@ -185,6 +186,11 @@ viewDetails, }) + const copyToClipboard = async value => { + await Helpers.copyToClipboard(value) + notifications.success("Copied") + } + onMount(async () => { await auditLogs.getEventDefinitions() }) @@ -246,6 +252,7 @@
event[0]} getOptionLabel={event => event[1]} @@ -318,6 +325,12 @@
+
copyToClipboard(JSON.stringify(selectedLog.metadata))} + class="copy-icon" + > + +
+ .copy-icon { + right: 16px; + top: 80px; + z-index: 10; + justify-content: center; + align-items: center; + display: flex; + flex-direction: row; + box-sizing: border-box; + + border: 1px solid var(--spectrum-alias-border-color); + border-radius: var(--spectrum-alias-border-radius-regular); + width: 31px; + color: var(--spectrum-alias-text-color); + background-color: var(--spectrum-global-color-gray-75); + transition: background-color + var(--spectrum-global-animation-duration-100, 130ms), + box-shadow var(--spectrum-global-animation-duration-100, 130ms), + border-color var(--spectrum-global-animation-duration-100, 130ms); + height: calc(var(--spectrum-alias-item-height-m) - 2px); + position: absolute; + } + .copy-icon:hover { + cursor: pointer; + color: var(--spectrum-alias-text-color-hover); + background-color: var(--spectrum-global-color-gray-50); + border-color: var(--spectrum-alias-border-color-hover); + } .side-panel-header { display: flex; padding: 20px 10px 10px 10px; @@ -346,7 +387,7 @@ .side-panel-body { padding: 10px; - height: 95%; + height: calc(100% - 67px); } #side-panel { position: absolute; @@ -357,11 +398,11 @@ border-left: var(--border-light); width: 320px; max-width: calc(100vw - 48px - 48px); - overflow: auto; - overflow-x: hidden; transform: translateX(100%); transition: transform 130ms ease-in-out; - height: calc(100% - 25px); + height: calc(100% - 24px); + overflow-y: hidden; + overflow-x: hidden; z-index: 2; } #side-panel.visible { @@ -373,15 +414,14 @@ } #side-panel :global(textarea) { - min-height: 202px !important; + min-height: 100% !important; background-color: var( --spectrum-textfield-m-background-color, var(--spectrum-global-color-gray-50) ); - color: var( - --spectrum-textfield-m-text-color, - var(--spectrum-alias-text-color) - ); + padding-top: var(--spacing-l); + padding-left: var(--spacing-l); + font-size: 13px; } .search :global(.spectrum-InputGroup) { From 9d6d7812449471dd1d917ae543cfa88e7ad241da Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 22 Feb 2023 13:04:16 +0000 Subject: [PATCH 093/273] Use `--runInBand` in CI only (#9771) * Use in CI only * Use scripts instead of ternary to pick up correct bash syntax --- packages/backend-core/package.json | 2 +- packages/backend-core/scripts/test.sh | 12 ++++++++++++ packages/server/package.json | 2 +- packages/server/scripts/test.sh | 12 ++++++++++++ packages/worker/package.json | 2 +- packages/worker/scripts/test.sh | 12 ++++++++++++ 6 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 packages/backend-core/scripts/test.sh create mode 100644 packages/server/scripts/test.sh create mode 100644 packages/worker/scripts/test.sh diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index bc8ec58a7f..a554ab09f1 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -18,7 +18,7 @@ "build:pro": "../../scripts/pro/build.sh", "postbuild": "yarn run build:pro", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", - "test": "jest --coverage --runInBand", + "test": "bash scripts/test.sh", "test:watch": "jest --watchAll" }, "dependencies": { diff --git a/packages/backend-core/scripts/test.sh b/packages/backend-core/scripts/test.sh new file mode 100644 index 0000000000..4bf1900984 --- /dev/null +++ b/packages/backend-core/scripts/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [[ -n $CI ]] +then + # --runInBand performs better in ci where resources are limited + echo "jest --coverage --runInBand" + jest --coverage --runInBand +else + # --maxWorkers performs better in development + echo "jest --coverage" + jest --coverage +fi \ No newline at end of file diff --git a/packages/server/package.json b/packages/server/package.json index 2eedd09fc9..4dc6951979 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -14,7 +14,7 @@ "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", "debug": "yarn build && node --expose-gc --inspect=9222 dist/index.js", "postbuild": "copyfiles -u 1 src/**/*.svelte dist/ && copyfiles -u 1 src/**/*.hbs dist/ && copyfiles -u 1 src/**/*.json dist/", - "test": "jest --coverage --runInBand", + "test": "bash scripts/test.sh", "test:watch": "jest --watch", "predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client", "build:docker": "yarn run predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION", diff --git a/packages/server/scripts/test.sh b/packages/server/scripts/test.sh new file mode 100644 index 0000000000..2f3f54cb25 --- /dev/null +++ b/packages/server/scripts/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [[ -n $CI ]] +then + # --runInBand performs better in ci where resources are limited + echo "jest --coverage --runInBand" + jest --coverage --runInBand +else + # --maxWorkers performs better in development + echo "jest --coverage --maxWorkers=2" + jest --coverage --maxWorkers=2 +fi \ No newline at end of file diff --git a/packages/worker/package.json b/packages/worker/package.json index f28a153247..61be3f8fdd 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -22,7 +22,7 @@ "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", "dev:builder": "npm run dev:stack:init && nodemon", - "test": "jest --coverage --runInBand", + "test": "bash scripts/test.sh", "test:watch": "jest --watch", "env:multi:enable": "node scripts/multiTenancy.js enable", "env:multi:disable": "node scripts/multiTenancy.js disable", diff --git a/packages/worker/scripts/test.sh b/packages/worker/scripts/test.sh new file mode 100644 index 0000000000..2f3f54cb25 --- /dev/null +++ b/packages/worker/scripts/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [[ -n $CI ]] +then + # --runInBand performs better in ci where resources are limited + echo "jest --coverage --runInBand" + jest --coverage --runInBand +else + # --maxWorkers performs better in development + echo "jest --coverage --maxWorkers=2" + jest --coverage --maxWorkers=2 +fi \ No newline at end of file From bfe07563738b441f4f80c8238d273dc4434c021b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:11:38 +0000 Subject: [PATCH 094/273] v2.3.18-alpha.4 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 3e05b82a1e..ce8b6c3658 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index a554ab09f1..53f24e87a3 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.3", + "@budibase/types": "2.3.18-alpha.4", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index c247e32e50..37b8294514 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "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.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.4", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index ed6fc08ac5..d364f93fb7 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.3", - "@budibase/client": "2.3.18-alpha.3", - "@budibase/frontend-core": "2.3.18-alpha.3", - "@budibase/string-templates": "2.3.18-alpha.3", + "@budibase/bbui": "2.3.18-alpha.4", + "@budibase/client": "2.3.18-alpha.4", + "@budibase/frontend-core": "2.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.4", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index ce9aa90b8f..a319c9d188 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "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.3.18-alpha.3", - "@budibase/string-templates": "2.3.18-alpha.3", - "@budibase/types": "2.3.18-alpha.3", + "@budibase/backend-core": "2.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.4", + "@budibase/types": "2.3.18-alpha.4", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index e0320f52ab..8c9294ead6 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "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.3.18-alpha.3", - "@budibase/frontend-core": "2.3.18-alpha.3", - "@budibase/string-templates": "2.3.18-alpha.3", + "@budibase/bbui": "2.3.18-alpha.4", + "@budibase/frontend-core": "2.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.4", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 9a9843af3b..7166498db9 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.3", + "@budibase/bbui": "2.3.18-alpha.4", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index d9d83c7889..047222af56 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 4dc6951979..66e07e1381 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "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.3.18-alpha.3", - "@budibase/client": "2.3.18-alpha.3", + "@budibase/backend-core": "2.3.18-alpha.4", + "@budibase/client": "2.3.18-alpha.4", "@budibase/pro": "2.3.18-alpha.3", - "@budibase/string-templates": "2.3.18-alpha.3", - "@budibase/types": "2.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.4", + "@budibase/types": "2.3.18-alpha.4", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 48081eda83..92c4712572 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 66959cf7c8..9f31a18c75 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 61be3f8fdd..9b51533697 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.3", + "version": "2.3.18-alpha.4", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.3", + "@budibase/backend-core": "2.3.18-alpha.4", "@budibase/pro": "2.3.18-alpha.3", - "@budibase/string-templates": "2.3.18-alpha.3", - "@budibase/types": "2.3.18-alpha.3", + "@budibase/string-templates": "2.3.18-alpha.4", + "@budibase/types": "2.3.18-alpha.4", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 52c362884618bdb6b43363ca0136551e09c667b3 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:14:32 +0000 Subject: [PATCH 095/273] Update pro version to 2.3.18-alpha.4 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 66e07e1381..b479c0219d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.4", "@budibase/client": "2.3.18-alpha.4", - "@budibase/pro": "2.3.18-alpha.3", + "@budibase/pro": "2.3.18-alpha.4", "@budibase/string-templates": "2.3.18-alpha.4", "@budibase/types": "2.3.18-alpha.4", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 3f6682875e..2b76c672fb 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.3.tgz#e10f4071cb43a178293b1ad37bcd1d4f45d358a1" - integrity sha512-MbaYwhvV1V9XrJTUP0wBy9fT9FtaJuAi1pOHJNWw3kvUEo7h5AiSp2hOGBoPJwoloeWQfZsJpglSOMA9HJf8fQ== +"@budibase/backend-core@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.4.tgz#b797aae1e91ce88c965b91d3607dc1c52b3e0ea5" + integrity sha512-FeHIFkLnZI6+iqNx93YUaLSsmnMkea6IsMPt34ljI8wspPRA5UP5fwGpeG5UPAD8uT8lETiBEEuFZWcdUVzx2g== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.3" + "@budibase/types" "2.3.18-alpha.4" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.3.tgz#73a759ee17600a340c41cb0c4f8d289bf66be66f" - integrity sha512-xNwzB7l5ZvxcqXMZgsaUVvPKufk3mgI/4TBGXB9IpYQRsGFFxrpNMRtQsMfWUEUrXBvFuyr/DPtQJekhrCcMxg== +"@budibase/pro@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.4.tgz#6ddeae46abc170380e6d53fda433509799878275" + integrity sha512-OoPtm+I25VAh8CZol7UzOChLqy40SGdyp8QNuKxpCoBKXNYiorJkIgllPUGgjHXQxeBJkSMMvKU+ie6/xlPQWg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.3" - "@budibase/types" "2.3.18-alpha.3" + "@budibase/backend-core" "2.3.18-alpha.4" + "@budibase/types" "2.3.18-alpha.4" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.3.tgz#a04a46784e833989f4cc7d4c45366a3cefb01f53" - integrity sha512-gkwJdM6zRXulwXQhjSsaDAjJyhbDMVhuFVDcQvS2oZBBrRtBFHfOqLw/dkTC6Zgq9ttu/00B1QihB+uliYRFLQ== +"@budibase/types@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.4.tgz#53b551af697bfc7f26123f92e6cac1c1615684c3" + integrity sha512-j0Y8IsWZ+6M+QvEex91YQQhb/uKmcxT7kWbMgRn4yrHFPYR/8mSlU0xLh5BhHB6DdIRjpaAyqMxLAe9FtSyigg== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index 9b51533697..fff469ff82 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.4", - "@budibase/pro": "2.3.18-alpha.3", + "@budibase/pro": "2.3.18-alpha.4", "@budibase/string-templates": "2.3.18-alpha.4", "@budibase/types": "2.3.18-alpha.4", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 123362b958..927ef329ff 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.3.tgz#e10f4071cb43a178293b1ad37bcd1d4f45d358a1" - integrity sha512-MbaYwhvV1V9XrJTUP0wBy9fT9FtaJuAi1pOHJNWw3kvUEo7h5AiSp2hOGBoPJwoloeWQfZsJpglSOMA9HJf8fQ== +"@budibase/backend-core@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.4.tgz#b797aae1e91ce88c965b91d3607dc1c52b3e0ea5" + integrity sha512-FeHIFkLnZI6+iqNx93YUaLSsmnMkea6IsMPt34ljI8wspPRA5UP5fwGpeG5UPAD8uT8lETiBEEuFZWcdUVzx2g== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.3" + "@budibase/types" "2.3.18-alpha.4" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.3.tgz#73a759ee17600a340c41cb0c4f8d289bf66be66f" - integrity sha512-xNwzB7l5ZvxcqXMZgsaUVvPKufk3mgI/4TBGXB9IpYQRsGFFxrpNMRtQsMfWUEUrXBvFuyr/DPtQJekhrCcMxg== +"@budibase/pro@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.4.tgz#6ddeae46abc170380e6d53fda433509799878275" + integrity sha512-OoPtm+I25VAh8CZol7UzOChLqy40SGdyp8QNuKxpCoBKXNYiorJkIgllPUGgjHXQxeBJkSMMvKU+ie6/xlPQWg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.3" - "@budibase/types" "2.3.18-alpha.3" + "@budibase/backend-core" "2.3.18-alpha.4" + "@budibase/types" "2.3.18-alpha.4" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.3": - version "2.3.18-alpha.3" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.3.tgz#a04a46784e833989f4cc7d4c45366a3cefb01f53" - integrity sha512-gkwJdM6zRXulwXQhjSsaDAjJyhbDMVhuFVDcQvS2oZBBrRtBFHfOqLw/dkTC6Zgq9ttu/00B1QihB+uliYRFLQ== +"@budibase/types@2.3.18-alpha.4": + version "2.3.18-alpha.4" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.4.tgz#53b551af697bfc7f26123f92e6cac1c1615684c3" + integrity sha512-j0Y8IsWZ+6M+QvEex91YQQhb/uKmcxT7kWbMgRn4yrHFPYR/8mSlU0xLh5BhHB6DdIRjpaAyqMxLAe9FtSyigg== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From fee091b081b112554ec80970f1d09388807bc9e2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 22 Feb 2023 13:22:59 +0000 Subject: [PATCH 096/273] Allow updating nested settings via conditional UI (#9748) * Allow updating nested settings via conditional UI * Tidy up comments * Improve safety when generating conditions --------- Co-authored-by: Rory Powell --- .../client/src/components/Component.svelte | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index a846a315bc..d94199bc49 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -72,6 +72,9 @@ // These are a combination of the enriched, nested and conditional settings. let cachedSettings + // Conditional UI expressions, enriched and ready to evaluate + let conditions + // Latest timestamp that we started a props update. // Due to enrichment now being async, we need to avoid overwriting newer // settings with old ones, depending on how long enrichment takes. @@ -150,9 +153,7 @@ $: enrichComponentSettings($context, settingsDefinitionMap) // Evaluate conditional UI settings and store any component setting changes - // which need to be made. This is broken into 2 lines to avoid svelte - // reactivity re-evaluating conditions more often than necessary. - $: conditions = enrichedSettings?._conditions + // which need to be made $: evaluateConditions(conditions) // Determine and apply settings to the component @@ -297,7 +298,7 @@ let newStaticSettings = { ...settings } let newDynamicSettings = { ...settings } - // Attach some internal properties + // Attach some internal properties which we assume always need enriched newDynamicSettings["_conditions"] = instance._conditions newDynamicSettings["_css"] = instance._styles?.custom @@ -336,6 +337,24 @@ } } + // Generates the array of conditional UI expressions, accounting for both + // nested and non-nested settings, extracting a mixture of values from both + // the un-enriched and enriched settings + const generateConditions = () => { + if (!enrichedSettings?._conditions) { + conditions = [] + return + } + conditions = enrichedSettings._conditions.map(condition => { + const raw = instance._conditions?.find(x => x.id === condition.id) + if (settingsDefinitionMap[condition.setting]?.nested && raw) { + return { ...condition, settingValue: raw.settingValue } + } else { + return condition + } + }) + } + // Enriches any string component props using handlebars const enrichComponentSettings = ( context, @@ -364,7 +383,11 @@ return } + // Store new enriched settings enrichedSettings = newEnrichedSettings + + // Once settings have been enriched, re-evaluate conditions + generateConditions() } // Evaluates the list of conditional UI conditions and determines any setting From 46c015491a5affeb98575650bcd3d6397e9c5e9c Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:33:55 +0000 Subject: [PATCH 097/273] v2.3.18-alpha.5 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index ce8b6c3658..2f560e521a 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 53f24e87a3..0bee6e9490 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.4", + "@budibase/types": "2.3.18-alpha.5", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 37b8294514..11d0ccf6a4 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "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.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.5", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index d364f93fb7..6ee5567a7c 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.4", - "@budibase/client": "2.3.18-alpha.4", - "@budibase/frontend-core": "2.3.18-alpha.4", - "@budibase/string-templates": "2.3.18-alpha.4", + "@budibase/bbui": "2.3.18-alpha.5", + "@budibase/client": "2.3.18-alpha.5", + "@budibase/frontend-core": "2.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.5", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index a319c9d188..2cb2476bee 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "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.3.18-alpha.4", - "@budibase/string-templates": "2.3.18-alpha.4", - "@budibase/types": "2.3.18-alpha.4", + "@budibase/backend-core": "2.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.5", + "@budibase/types": "2.3.18-alpha.5", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 8c9294ead6..06c2e9e0f4 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "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.3.18-alpha.4", - "@budibase/frontend-core": "2.3.18-alpha.4", - "@budibase/string-templates": "2.3.18-alpha.4", + "@budibase/bbui": "2.3.18-alpha.5", + "@budibase/frontend-core": "2.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.5", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 7166498db9..8fd8942b0f 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.4", + "@budibase/bbui": "2.3.18-alpha.5", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 047222af56..4e148980a4 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index b479c0219d..663cf09bf9 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "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.3.18-alpha.4", - "@budibase/client": "2.3.18-alpha.4", + "@budibase/backend-core": "2.3.18-alpha.5", + "@budibase/client": "2.3.18-alpha.5", "@budibase/pro": "2.3.18-alpha.4", - "@budibase/string-templates": "2.3.18-alpha.4", - "@budibase/types": "2.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.5", + "@budibase/types": "2.3.18-alpha.5", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 92c4712572..ab2525db46 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index 9f31a18c75..b51b39b842 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index fff469ff82..c632a630ca 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.4", + "version": "2.3.18-alpha.5", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.4", + "@budibase/backend-core": "2.3.18-alpha.5", "@budibase/pro": "2.3.18-alpha.4", - "@budibase/string-templates": "2.3.18-alpha.4", - "@budibase/types": "2.3.18-alpha.4", + "@budibase/string-templates": "2.3.18-alpha.5", + "@budibase/types": "2.3.18-alpha.5", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From e04c72331e5697b68a3859d3f56b264bb627a07b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:37:06 +0000 Subject: [PATCH 098/273] Update pro version to 2.3.18-alpha.5 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index 663cf09bf9..aae4598e91 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.5", "@budibase/client": "2.3.18-alpha.5", - "@budibase/pro": "2.3.18-alpha.4", + "@budibase/pro": "2.3.18-alpha.5", "@budibase/string-templates": "2.3.18-alpha.5", "@budibase/types": "2.3.18-alpha.5", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 2b76c672fb..18ed4f5844 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.4.tgz#b797aae1e91ce88c965b91d3607dc1c52b3e0ea5" - integrity sha512-FeHIFkLnZI6+iqNx93YUaLSsmnMkea6IsMPt34ljI8wspPRA5UP5fwGpeG5UPAD8uT8lETiBEEuFZWcdUVzx2g== +"@budibase/backend-core@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.5.tgz#8f93a64114d9dc7a513b2eb9dbd6e91a0c087c76" + integrity sha512-jZEVbU/L2Dyuwgtr4qhph1BFSUCkj14UIIV7WrC+CkmMixxQZHuO3pim9n7/kJ5GLE859sI42kOu+quS8YmqKA== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.4" + "@budibase/types" "2.3.18-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.4.tgz#6ddeae46abc170380e6d53fda433509799878275" - integrity sha512-OoPtm+I25VAh8CZol7UzOChLqy40SGdyp8QNuKxpCoBKXNYiorJkIgllPUGgjHXQxeBJkSMMvKU+ie6/xlPQWg== +"@budibase/pro@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.5.tgz#7dd0fab4dc7e55e7cc86ec61df6fe9ff72eae525" + integrity sha512-a0pSR/BgWCI1u7AMOrfGeiEq9YZeMWq5ASU3yzZsH9HRP35diEdDWMiiMoGjVZvJpzHQb3caTSNCbMWjfW4aQg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.4" - "@budibase/types" "2.3.18-alpha.4" + "@budibase/backend-core" "2.3.18-alpha.5" + "@budibase/types" "2.3.18-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.4.tgz#53b551af697bfc7f26123f92e6cac1c1615684c3" - integrity sha512-j0Y8IsWZ+6M+QvEex91YQQhb/uKmcxT7kWbMgRn4yrHFPYR/8mSlU0xLh5BhHB6DdIRjpaAyqMxLAe9FtSyigg== +"@budibase/types@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.5.tgz#2dc82d2899ae3b320a16fbad47ce6226a68efb52" + integrity sha512-zjHGgIZwZbMzeOn+RoMxD+PTxG7Iebi4iyMRvhPN1cBi89SBdS1SLnCm0thcZ9yEvgGdjLSEtV71oIBnapbQqA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index c632a630ca..5e75cb0783 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.5", - "@budibase/pro": "2.3.18-alpha.4", + "@budibase/pro": "2.3.18-alpha.5", "@budibase/string-templates": "2.3.18-alpha.5", "@budibase/types": "2.3.18-alpha.5", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 927ef329ff..3ac7f166ac 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.4.tgz#b797aae1e91ce88c965b91d3607dc1c52b3e0ea5" - integrity sha512-FeHIFkLnZI6+iqNx93YUaLSsmnMkea6IsMPt34ljI8wspPRA5UP5fwGpeG5UPAD8uT8lETiBEEuFZWcdUVzx2g== +"@budibase/backend-core@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.5.tgz#8f93a64114d9dc7a513b2eb9dbd6e91a0c087c76" + integrity sha512-jZEVbU/L2Dyuwgtr4qhph1BFSUCkj14UIIV7WrC+CkmMixxQZHuO3pim9n7/kJ5GLE859sI42kOu+quS8YmqKA== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.4" + "@budibase/types" "2.3.18-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.4.tgz#6ddeae46abc170380e6d53fda433509799878275" - integrity sha512-OoPtm+I25VAh8CZol7UzOChLqy40SGdyp8QNuKxpCoBKXNYiorJkIgllPUGgjHXQxeBJkSMMvKU+ie6/xlPQWg== +"@budibase/pro@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.5.tgz#7dd0fab4dc7e55e7cc86ec61df6fe9ff72eae525" + integrity sha512-a0pSR/BgWCI1u7AMOrfGeiEq9YZeMWq5ASU3yzZsH9HRP35diEdDWMiiMoGjVZvJpzHQb3caTSNCbMWjfW4aQg== dependencies: - "@budibase/backend-core" "2.3.18-alpha.4" - "@budibase/types" "2.3.18-alpha.4" + "@budibase/backend-core" "2.3.18-alpha.5" + "@budibase/types" "2.3.18-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.4": - version "2.3.18-alpha.4" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.4.tgz#53b551af697bfc7f26123f92e6cac1c1615684c3" - integrity sha512-j0Y8IsWZ+6M+QvEex91YQQhb/uKmcxT7kWbMgRn4yrHFPYR/8mSlU0xLh5BhHB6DdIRjpaAyqMxLAe9FtSyigg== +"@budibase/types@2.3.18-alpha.5": + version "2.3.18-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.5.tgz#2dc82d2899ae3b320a16fbad47ce6226a68efb52" + integrity sha512-zjHGgIZwZbMzeOn+RoMxD+PTxG7Iebi4iyMRvhPN1cBi89SBdS1SLnCm0thcZ9yEvgGdjLSEtV71oIBnapbQqA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 4b85583f5f0697d1b86a516750e803890c122f6e Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 22 Feb 2023 13:39:31 +0000 Subject: [PATCH 099/273] Update builder and authorized middleware to be more strict towards unauthenticated (#9774) * Update builder and authorized middleware to be more strict towards unauthenticated * Remove unnecessary variable --- packages/server/src/middleware/authorized.ts | 10 ++++++---- packages/server/src/middleware/builder.ts | 11 ++++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/server/src/middleware/authorized.ts b/packages/server/src/middleware/authorized.ts index d3fd4de81d..6268163fb2 100644 --- a/packages/server/src/middleware/authorized.ts +++ b/packages/server/src/middleware/authorized.ts @@ -79,10 +79,6 @@ export default ( 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) - // get the resource roles let resourceRoles: any = [] let otherLevelRoles: any = [] @@ -112,6 +108,12 @@ export default ( return ctx.throw(403, "Session not authenticated") } + // check general builder stuff, this middleware is a good way + // to find API endpoints which are builder focused + if (permType === permissions.PermissionType.BUILDER) { + await builderMiddleware(ctx) + } + try { // check authorized await checkAuthorized(ctx, resourceRoles, permType, permLevel) diff --git a/packages/server/src/middleware/builder.ts b/packages/server/src/middleware/builder.ts index 7df6c7ad33..5174f618a0 100644 --- a/packages/server/src/middleware/builder.ts +++ b/packages/server/src/middleware/builder.ts @@ -64,13 +64,18 @@ async function updateAppUpdatedAt(ctx: BBContext) { }) } -export default async function builder(ctx: BBContext, permType: string) { +export default async function builder(ctx: BBContext) { const appId = ctx.appId // this only functions within an app context if (!appId) { return } - const isBuilderApi = permType === permissions.PermissionType.BUILDER + + // check authenticated + if (!ctx.isAuthenticated) { + return ctx.throw(403, "Session not authenticated") + } + const referer = ctx.headers["referer"] const overviewPath = "/builder/portal/overview/" @@ -82,7 +87,7 @@ export default async function builder(ctx: BBContext, permType: string) { const hasAppId = !referer ? false : referer.includes(appId) const editingApp = referer ? hasAppId : false // check this is a builder call and editing - if (!isBuilderApi || !editingApp) { + if (!editingApp) { return } // check locks From 8cb9d5067beba8153d0d2c751e1a6ea6587c7221 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:56:31 +0000 Subject: [PATCH 100/273] v2.3.18-alpha.6 --- lerna.json | 2 +- packages/backend-core/package.json | 4 ++-- packages/bbui/package.json | 4 ++-- packages/builder/package.json | 10 +++++----- packages/cli/package.json | 8 ++++---- packages/client/package.json | 8 ++++---- packages/frontend-core/package.json | 4 ++-- packages/sdk/package.json | 2 +- packages/server/package.json | 10 +++++----- packages/string-templates/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 8 ++++---- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lerna.json b/lerna.json index 2f560e521a..0a3d923d6c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 0bee6e9490..479a54bd94 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.1", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.5", + "@budibase/types": "2.3.18-alpha.6", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 11d0ccf6a4..6cfeb44a7b 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "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.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.6", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 6ee5567a7c..77b09fdbf3 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.5", - "@budibase/client": "2.3.18-alpha.5", - "@budibase/frontend-core": "2.3.18-alpha.5", - "@budibase/string-templates": "2.3.18-alpha.5", + "@budibase/bbui": "2.3.18-alpha.6", + "@budibase/client": "2.3.18-alpha.6", + "@budibase/frontend-core": "2.3.18-alpha.6", + "@budibase/string-templates": "2.3.18-alpha.6", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 2cb2476bee..49f7a6ab6b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "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.3.18-alpha.5", - "@budibase/string-templates": "2.3.18-alpha.5", - "@budibase/types": "2.3.18-alpha.5", + "@budibase/backend-core": "2.3.18-alpha.6", + "@budibase/string-templates": "2.3.18-alpha.6", + "@budibase/types": "2.3.18-alpha.6", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/package.json b/packages/client/package.json index 06c2e9e0f4..b848ae691e 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "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.3.18-alpha.5", - "@budibase/frontend-core": "2.3.18-alpha.5", - "@budibase/string-templates": "2.3.18-alpha.5", + "@budibase/bbui": "2.3.18-alpha.6", + "@budibase/frontend-core": "2.3.18-alpha.6", + "@budibase/string-templates": "2.3.18-alpha.6", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 8fd8942b0f..8328865966 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,12 +1,12 @@ { "name": "@budibase/frontend-core", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.3.18-alpha.5", + "@budibase/bbui": "2.3.18-alpha.6", "lodash": "^4.17.21", "svelte": "^3.46.2" } diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 4e148980a4..a44a61274d 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index aae4598e91..d85bb6db2c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "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.3.18-alpha.5", - "@budibase/client": "2.3.18-alpha.5", + "@budibase/backend-core": "2.3.18-alpha.6", + "@budibase/client": "2.3.18-alpha.6", "@budibase/pro": "2.3.18-alpha.5", - "@budibase/string-templates": "2.3.18-alpha.5", - "@budibase/types": "2.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.6", + "@budibase/types": "2.3.18-alpha.6", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index ab2525db46..82b97419ef 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index b51b39b842..f1a9adfa2f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Budibase types", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/worker/package.json b/packages/worker/package.json index 5e75cb0783..e6df349624 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.3.18-alpha.5", + "version": "2.3.18-alpha.6", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.3.18-alpha.5", + "@budibase/backend-core": "2.3.18-alpha.6", "@budibase/pro": "2.3.18-alpha.5", - "@budibase/string-templates": "2.3.18-alpha.5", - "@budibase/types": "2.3.18-alpha.5", + "@budibase/string-templates": "2.3.18-alpha.6", + "@budibase/types": "2.3.18-alpha.6", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", From 96dfa32c0b531d1fbc173c46cc85caafa5a8fea1 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 22 Feb 2023 13:59:23 +0000 Subject: [PATCH 101/273] Update pro version to 2.3.18-alpha.6 --- packages/server/package.json | 2 +- packages/server/yarn.lock | 30 +++++++++++++++--------------- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 30 +++++++++++++++--------------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index d85bb6db2c..c183a808b8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -45,7 +45,7 @@ "@apidevtools/swagger-parser": "10.0.3", "@budibase/backend-core": "2.3.18-alpha.6", "@budibase/client": "2.3.18-alpha.6", - "@budibase/pro": "2.3.18-alpha.5", + "@budibase/pro": "2.3.18-alpha.6", "@budibase/string-templates": "2.3.18-alpha.6", "@budibase/types": "2.3.18-alpha.6", "@bull-board/api": "3.7.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 18ed4f5844..04d1b7759f 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1278,14 +1278,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.5.tgz#8f93a64114d9dc7a513b2eb9dbd6e91a0c087c76" - integrity sha512-jZEVbU/L2Dyuwgtr4qhph1BFSUCkj14UIIV7WrC+CkmMixxQZHuO3pim9n7/kJ5GLE859sI42kOu+quS8YmqKA== +"@budibase/backend-core@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.6.tgz#e6b3304e96b9469f3ca0f4fcfda8cf234c37e2d7" + integrity sha512-To0kFbB9nZ6p0UO4ScS4PJ0gbqI1PrMWRXJLTv/6GU3PxnsqvH1tbpcleLMz2zeE04e5xdwt6W1oPViELom2gg== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.5" + "@budibase/types" "2.3.18-alpha.6" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1392,13 +1392,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.5.tgz#7dd0fab4dc7e55e7cc86ec61df6fe9ff72eae525" - integrity sha512-a0pSR/BgWCI1u7AMOrfGeiEq9YZeMWq5ASU3yzZsH9HRP35diEdDWMiiMoGjVZvJpzHQb3caTSNCbMWjfW4aQg== +"@budibase/pro@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.6.tgz#7c5c221da7da79af79605a00aacac5c60f209bf6" + integrity sha512-YWPxmZn+z3tm5GZ+2UZSkOAhamlue/dmki+FCML5pIp3dCw8KsXnpzYXHRc1F8yXMTmA/8KBb/YkjQ2WK3Rk7A== dependencies: - "@budibase/backend-core" "2.3.18-alpha.5" - "@budibase/types" "2.3.18-alpha.5" + "@budibase/backend-core" "2.3.18-alpha.6" + "@budibase/types" "2.3.18-alpha.6" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1424,10 +1424,10 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" -"@budibase/types@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.5.tgz#2dc82d2899ae3b320a16fbad47ce6226a68efb52" - integrity sha512-zjHGgIZwZbMzeOn+RoMxD+PTxG7Iebi4iyMRvhPN1cBi89SBdS1SLnCm0thcZ9yEvgGdjLSEtV71oIBnapbQqA== +"@budibase/types@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.6.tgz#9438ee64008668bbcb3d688b189cc649e03dfd60" + integrity sha512-16YtXwSODS8UDhdxCP2piGDWELP05EZuPbwLsOUFLX3Gt0+Wwkme+XWw4pTPE+GoK/mTVkDxzSc4cvuXWtfxxA== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/worker/package.json b/packages/worker/package.json index e6df349624..2854f35441 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -37,7 +37,7 @@ "license": "GPL-3.0", "dependencies": { "@budibase/backend-core": "2.3.18-alpha.6", - "@budibase/pro": "2.3.18-alpha.5", + "@budibase/pro": "2.3.18-alpha.6", "@budibase/string-templates": "2.3.18-alpha.6", "@budibase/types": "2.3.18-alpha.6", "@koa/router": "8.0.8", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 3ac7f166ac..7d296fe01b 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.5.tgz#8f93a64114d9dc7a513b2eb9dbd6e91a0c087c76" - integrity sha512-jZEVbU/L2Dyuwgtr4qhph1BFSUCkj14UIIV7WrC+CkmMixxQZHuO3pim9n7/kJ5GLE859sI42kOu+quS8YmqKA== +"@budibase/backend-core@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.3.18-alpha.6.tgz#e6b3304e96b9469f3ca0f4fcfda8cf234c37e2d7" + integrity sha512-To0kFbB9nZ6p0UO4ScS4PJ0gbqI1PrMWRXJLTv/6GU3PxnsqvH1tbpcleLMz2zeE04e5xdwt6W1oPViELom2gg== dependencies: "@budibase/nano" "10.1.1" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.3.18-alpha.5" + "@budibase/types" "2.3.18-alpha.6" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -539,13 +539,13 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.5.tgz#7dd0fab4dc7e55e7cc86ec61df6fe9ff72eae525" - integrity sha512-a0pSR/BgWCI1u7AMOrfGeiEq9YZeMWq5ASU3yzZsH9HRP35diEdDWMiiMoGjVZvJpzHQb3caTSNCbMWjfW4aQg== +"@budibase/pro@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.3.18-alpha.6.tgz#7c5c221da7da79af79605a00aacac5c60f209bf6" + integrity sha512-YWPxmZn+z3tm5GZ+2UZSkOAhamlue/dmki+FCML5pIp3dCw8KsXnpzYXHRc1F8yXMTmA/8KBb/YkjQ2WK3Rk7A== dependencies: - "@budibase/backend-core" "2.3.18-alpha.5" - "@budibase/types" "2.3.18-alpha.5" + "@budibase/backend-core" "2.3.18-alpha.6" + "@budibase/types" "2.3.18-alpha.6" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -553,10 +553,10 @@ lru-cache "^7.14.1" node-fetch "^2.6.1" -"@budibase/types@2.3.18-alpha.5": - version "2.3.18-alpha.5" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.5.tgz#2dc82d2899ae3b320a16fbad47ce6226a68efb52" - integrity sha512-zjHGgIZwZbMzeOn+RoMxD+PTxG7Iebi4iyMRvhPN1cBi89SBdS1SLnCm0thcZ9yEvgGdjLSEtV71oIBnapbQqA== +"@budibase/types@2.3.18-alpha.6": + version "2.3.18-alpha.6" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.3.18-alpha.6.tgz#9438ee64008668bbcb3d688b189cc649e03dfd60" + integrity sha512-16YtXwSODS8UDhdxCP2piGDWELP05EZuPbwLsOUFLX3Gt0+Wwkme+XWw4pTPE+GoK/mTVkDxzSc4cvuXWtfxxA== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" From 63af59a5b0038f1517ac6c8381a5fe5ffe1e3230 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 14:59:42 +0100 Subject: [PATCH 102/273] Handle link fields --- .../src/api/controllers/row/ExternalRequest.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 56e54e299e..a262df8d69 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -177,9 +177,14 @@ function getEndpoint(tableId: string | undefined, operation: string) { function basicProcessing(row: Row, table: Table): Row { const thisRow: Row = {} // filter the row down to what is actually the row (not joined) - for (let fieldName of Object.keys(table.schema)) { + for (let field of Object.values(table.schema)) { + const fieldName = field.name + const pathValue = row[`${table.name}.${fieldName}`] - const value = pathValue != null ? pathValue : row[fieldName] + const value = + pathValue != null || field.type === FieldTypes.LINK + ? pathValue + : row[fieldName] // all responses include "select col as table.col" so that overlaps are handled if (value != null) { thisRow[fieldName] = value @@ -572,11 +577,18 @@ export class ExternalRequest { if (!linkTable || !linkPrimary) { return } + + const linkSecondary = + linkTable?.primary && + linkTable?.primary?.length > 1 && + linkTable?.primary[1] + const rows = related[key]?.rows || [] const found = rows.find( (row: { [key: string]: any }) => row[linkPrimary] === relationship.id || - row[linkPrimary] === body?.[linkPrimary] + (row[linkPrimary] === body?.[linkPrimary] && + (!linkSecondary || row[linkSecondary] === body?.[linkSecondary])) ) const operation = isUpdate ? Operation.UPDATE : Operation.CREATE if (!found) { From c6dadaa4ff524005a719a6d3fbe00f1e2044fd4c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 22 Feb 2023 16:10:54 +0000 Subject: [PATCH 103/273] Some work to make sure the user agent and ip address are always passed correctly to audit logs. --- packages/backend-core/src/events/events.ts | 28 +++++++++---------- .../backend-core/src/events/identification.ts | 2 +- packages/backend-core/src/events/index.ts | 2 +- packages/types/src/sdk/auditLogs.ts | 6 ++++ .../types/src/sdk/events/identification.ts | 2 +- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/backend-core/src/events/events.ts b/packages/backend-core/src/events/events.ts index 6176fb6724..d3d32384aa 100644 --- a/packages/backend-core/src/events/events.ts +++ b/packages/backend-core/src/events/events.ts @@ -1,4 +1,10 @@ -import { AuditLogFn, Event, IdentityType, HostInfo } from "@budibase/types" +import { + AuditLogFn, + Event, + IdentityType, + AuditedEventFriendlyName, + AuditLogQueueEvent, +} from "@budibase/types" import { processors } from "./processors" import identification from "./identification" import { getAppId } from "../context" @@ -6,24 +12,17 @@ import * as backfill from "./backfill" import { createQueue, JobQueue } from "../queue" import BullQueue from "bull" -type AuditLogEvent = { - event: Event - properties: any - opts: { - timestamp?: string | number - userId?: string - appId?: string - hostInfo?: HostInfo - } +export function isAudited(event: Event) { + return !!AuditedEventFriendlyName[event] } let auditLogsEnabled = false -let auditLogQueue: BullQueue.Queue +let auditLogQueue: BullQueue.Queue export const configure = (fn: AuditLogFn) => { auditLogsEnabled = true const writeAuditLogs = fn - auditLogQueue = createQueue(JobQueue.AUDIT_LOG) + auditLogQueue = createQueue(JobQueue.AUDIT_LOG) return auditLogQueue.process(async job => { await writeAuditLogs(job.data.event, job.data.properties, { userId: job.data.opts.userId, @@ -46,11 +45,11 @@ export const publishEvent = async ( // no backfill - send the event and exit if (!backfilling) { await processors.processEvent(event, identity, properties, timestamp) - if (auditLogsEnabled) { + if (auditLogsEnabled && isAudited(event)) { // only audit log actual events, don't include backfills const userId = identity.type === IdentityType.USER ? identity.id : undefined - // add to event queue, rather than just writing immediately + // add to the event queue, rather than just writing immediately await auditLogQueue.add({ event, properties, @@ -58,6 +57,7 @@ export const publishEvent = async ( userId, timestamp, appId: getAppId(), + hostInfo: identity.hostInfo, }, }) } diff --git a/packages/backend-core/src/events/identification.ts b/packages/backend-core/src/events/identification.ts index e18d96bbe0..dcb2ebb4ab 100644 --- a/packages/backend-core/src/events/identification.ts +++ b/packages/backend-core/src/events/identification.ts @@ -89,7 +89,7 @@ const getCurrentIdentity = async (): Promise => { installationId, tenantId, environment, - hostInfo: userContext.host, + hostInfo: userContext.hostInfo, } } else { throw new Error("Unknown identity type") diff --git a/packages/backend-core/src/events/index.ts b/packages/backend-core/src/events/index.ts index 7aa4d06e58..15f6dde835 100644 --- a/packages/backend-core/src/events/index.ts +++ b/packages/backend-core/src/events/index.ts @@ -3,7 +3,7 @@ export * as processors from "./processors" export * as analytics from "./analytics" export { default as identification } from "./identification" export * as backfillCache from "./backfill" -export { configure } from "./events" +export { configure, isAudited } from "./events" import { processors } from "./processors" diff --git a/packages/types/src/sdk/auditLogs.ts b/packages/types/src/sdk/auditLogs.ts index dea36b0164..e5d0c77d90 100644 --- a/packages/types/src/sdk/auditLogs.ts +++ b/packages/types/src/sdk/auditLogs.ts @@ -12,3 +12,9 @@ export type AuditLogFn = ( metadata: any, opts: AuditWriteOpts ) => Promise + +export type AuditLogQueueEvent = { + event: Event + properties: any + opts: AuditWriteOpts +} diff --git a/packages/types/src/sdk/events/identification.ts b/packages/types/src/sdk/events/identification.ts index bbbf74d33e..8b6b7ddf44 100644 --- a/packages/types/src/sdk/events/identification.ts +++ b/packages/types/src/sdk/events/identification.ts @@ -46,7 +46,7 @@ export interface Identity { environment: string installationId?: string tenantId?: string - hostInfo: HostInfo + hostInfo?: HostInfo } export interface UserIdentity extends Identity { From f00994af7f015d4792e14450178f23a0d55c7f94 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 17:18:05 +0100 Subject: [PATCH 104/273] Fix wrong relationship mapping --- .../server/src/api/controllers/row/ExternalRequest.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index a262df8d69..1510e31881 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -384,6 +384,15 @@ export class ExternalRequest { ) { continue } + + if ( + relationship.from && + row[fromColumn] === undefined && + row[relationship.from] === null + ) { + continue + } + let linked = basicProcessing(row, linkedTable) if (!linked._id) { continue From 647e643439d12899b9a00293db0d8e91f84f7505 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 22 Feb 2023 17:25:24 +0000 Subject: [PATCH 105/273] start download work --- .../portal/account/auditLogs/index.svelte | 27 +++++++++++++++---- packages/frontend-core/src/api/auditLogs.js | 6 ++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 4459eb12a5..125a67a03d 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -21,6 +21,7 @@ import UserRenderer from "./_components/UserRenderer.svelte" import TimeRenderer from "./_components/TimeRenderer.svelte" import AppColumnRenderer from "./_components/AppColumnRenderer.svelte" + import download from "downloadjs" const schema = { date: { width: "0.8fr" }, @@ -167,16 +168,29 @@ selectedLog = detail sidePanelVisible = true } + async function exportView() { + try { + const data = await API.exportView({ + viewName: view, + format: exportFormat, + }) + } catch (error) { + notifications.error(`Unable to export ${exportFormat.toUpperCase()} data`) + } + } const downloadLogs = async () => { try { - await auditLogs.download({ + let response = await auditLogs.downloadLogs({ startDate, endDate, - metadataSearch: logSearchTerm, + fullSearch: logSearchTerm, userIds: selectedUsers, appIds: selectedApps, + events: selectedEvents, }) + + // DO SOMETHING HERE??????????? } catch (error) { notifications.error(`Error downloading logs: ` + error.message) } @@ -193,6 +207,7 @@ onMount(async () => { await auditLogs.getEventDefinitions() + await licensing.init() }) @@ -214,7 +229,6 @@ range={true} label="Date Range" on:change={e => { - console.log(e) if (e.detail[0]?.length === 1) { startDate = e.detail[0][0].toISOString() } else if (e.detail[0]?.length > 1) { @@ -263,8 +277,11 @@ />
-
- downloadLogs()} name="Download" /> +
downloadLogs()} + style="padding-bottom: var(--spacing-s)" + > +
diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 867644c23c..08e14328a1 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -8,7 +8,7 @@ const buildOpts = ({ events, }) => { const opts = {} - + if (bookmark) { opts.bookmark = bookmark } @@ -35,7 +35,7 @@ const buildOpts = ({ if (appIds.length) { opts.appIds = appIds } - + console.log(opts) return opts } @@ -58,7 +58,7 @@ export const buildAuditLogsEndpoints = API => ({ downloadLogs: async opts => { return await API.post({ - url: `/api/global/auditlogs/definitions`, + url: `/api/global/auditlogs/download`, body: buildOpts(opts), }) }, From 01076bd35f896d12a539dcb8b39ad858fe3c87be Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 22 Feb 2023 18:50:27 +0000 Subject: [PATCH 106/273] Getting downloading working correctly, some minor UI updates, adding a new middleware for converting a query string to a body (useful for when a GET has to be used). --- .../src/middleware/downloadBody.ts | 22 ++++++++ packages/backend-core/src/middleware/index.ts | 1 + .../portal/account/auditLogs/index.svelte | 50 +++++++++---------- .../builder/src/stores/portal/auditLogs.js | 6 +-- packages/frontend-core/src/api/auditLogs.js | 10 ++-- .../api/routes/global/tests/auditLogs.spec.ts | 5 ++ 6 files changed, 60 insertions(+), 34 deletions(-) create mode 100644 packages/backend-core/src/middleware/downloadBody.ts create mode 100644 packages/worker/src/api/routes/global/tests/auditLogs.spec.ts diff --git a/packages/backend-core/src/middleware/downloadBody.ts b/packages/backend-core/src/middleware/downloadBody.ts new file mode 100644 index 0000000000..a7050e08c5 --- /dev/null +++ b/packages/backend-core/src/middleware/downloadBody.ts @@ -0,0 +1,22 @@ +import { Ctx } from "@budibase/types" + +/** + * Expects a standard "query" query string property which is the JSON body + * of the request, which has to be sent via query string due to the requirement + * of making an endpoint a GET request e.g. downloading a file stream. + */ +export default function (ctx: Ctx, next: any) { + const queryString = ctx.request.query?.query as string | undefined + if (!queryString) { + return next() + } + const decoded = decodeURIComponent(queryString) + let json + try { + json = JSON.parse(decoded) + } catch (err) { + return next() + } + ctx.request.body = json + return next() +} diff --git a/packages/backend-core/src/middleware/index.ts b/packages/backend-core/src/middleware/index.ts index de609f9a3e..0c4c2f6b94 100644 --- a/packages/backend-core/src/middleware/index.ts +++ b/packages/backend-core/src/middleware/index.ts @@ -17,4 +17,5 @@ export { default as builderOrAdmin } from "./builderOrAdmin" export { default as builderOnly } from "./builderOnly" export { default as logging } from "./logging" export { default as errorHandling } from "./errorHandling" +export { default as downloadBody } from "./downloadBody" export * as joiValidator from "./joi-validator" diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 125a67a03d..944ed87d1a 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -21,13 +21,13 @@ import UserRenderer from "./_components/UserRenderer.svelte" import TimeRenderer from "./_components/TimeRenderer.svelte" import AppColumnRenderer from "./_components/AppColumnRenderer.svelte" - import download from "downloadjs" + import { cloneDeep } from "lodash" const schema = { date: { width: "0.8fr" }, user: { width: "0.5fr" }, - app: { width: "1fr", fieldName: "name" }, - name: { width: "1fr" }, + app: { width: "0.75fr", fieldName: "name" }, + name: { width: "1.5fr" }, view: { width: "auto", borderLeft: true, displayName: "" }, } @@ -134,8 +134,7 @@ $auditLogs.logs.bookmark ) } catch (error) { - console.log(error) - notifications.error("Error getting audit logs") + notifications.error(`Error getting audit logs - ${error}`) } } @@ -164,24 +163,13 @@ } const viewDetails = detail => { - console.log(detail) selectedLog = detail sidePanelVisible = true } - async function exportView() { - try { - const data = await API.exportView({ - viewName: view, - format: exportFormat, - }) - } catch (error) { - notifications.error(`Unable to export ${exportFormat.toUpperCase()} data`) - } - } const downloadLogs = async () => { try { - let response = await auditLogs.downloadLogs({ + window.location = auditLogs.getDownloadUrl({ startDate, endDate, fullSearch: logSearchTerm, @@ -189,8 +177,6 @@ appIds: selectedApps, events: selectedEvents, }) - - // DO SOMETHING HERE??????????? } catch (error) { notifications.error(`Error downloading logs: ` + error.message) } @@ -205,6 +191,20 @@ notifications.success("Copied") } + function cleanupMetadata(log) { + const cloned = cloneDeep(log) + cloned.userId = cloned.user._id + if (cloned.app) { + cloned.appId = cloned.app.appId + } + // remove props that are confused/not returned in download + delete cloned._id + delete cloned._rev + delete cloned.app + delete cloned.user + return cloned + } + onMount(async () => { await auditLogs.getEventDefinitions() await licensing.init() @@ -277,15 +277,15 @@ />
+
+ +
+
downloadLogs()} style="padding-bottom: var(--spacing-s)" > - -
- -
- +
@@ -352,7 +352,7 @@ disabled minHeight={"300px"} height={"100%"} - value={JSON.stringify(selectedLog.metadata, null, 2)} + value={JSON.stringify(cleanupMetadata(selectedLog), null, 2)} /> diff --git a/packages/builder/src/stores/portal/auditLogs.js b/packages/builder/src/stores/portal/auditLogs.js index 165e4b5ec5..9abf8ec11b 100644 --- a/packages/builder/src/stores/portal/auditLogs.js +++ b/packages/builder/src/stores/portal/auditLogs.js @@ -28,15 +28,15 @@ export function createAuditLogsStore() { }) } - async function downloadLogs(opts = {}) { - return await API.downloadLogs(opts) + function getDownloadUrl(opts = {}) { + return API.getDownloadUrl(opts) } return { subscribe, search, getEventDefinitions, - downloadLogs, + getDownloadUrl, } } diff --git a/packages/frontend-core/src/api/auditLogs.js b/packages/frontend-core/src/api/auditLogs.js index 08e14328a1..b8ad16a722 100644 --- a/packages/frontend-core/src/api/auditLogs.js +++ b/packages/frontend-core/src/api/auditLogs.js @@ -8,7 +8,7 @@ const buildOpts = ({ events, }) => { const opts = {} - + if (bookmark) { opts.bookmark = bookmark } @@ -56,10 +56,8 @@ export const buildAuditLogsEndpoints = API => ({ }) }, - downloadLogs: async opts => { - return await API.post({ - url: `/api/global/auditlogs/download`, - body: buildOpts(opts), - }) + getDownloadUrl: opts => { + const query = encodeURIComponent(JSON.stringify(opts)) + return `/api/global/auditlogs/download?query=${query}` }, }) diff --git a/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts b/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts new file mode 100644 index 0000000000..5e7ed31263 --- /dev/null +++ b/packages/worker/src/api/routes/global/tests/auditLogs.spec.ts @@ -0,0 +1,5 @@ +import { mocks } from "@budibase/backend-core/tests" + +mocks.licenses.useEnvironmentVariables() + +describe("/api/global/auditlogs", () => {}) From 83649f1959e35d894b50cc44097c9a2f9520e749 Mon Sep 17 00:00:00 2001 From: adrinr Date: Wed, 22 Feb 2023 22:40:50 +0100 Subject: [PATCH 107/273] Setup o2m and m2m relationships --- .tool-versions | 2 +- .../api/controllers/row/ExternalRequest.ts | 32 ++--- .../src/integration-test/postgres.spec.ts | 134 +++++++++++------- 3 files changed, 100 insertions(+), 68 deletions(-) diff --git a/.tool-versions b/.tool-versions index 8a1af3c071..6ee8cc60be 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ nodejs 14.19.3 -python 3.11.1 \ No newline at end of file +python 3.10.0 \ No newline at end of file diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 1510e31881..79a598edf0 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -142,7 +142,11 @@ function cleanupConfig(config: RunConfig, table: Table): RunConfig { return config } -function generateIdForRow(row: Row | undefined, table: Table): string { +function generateIdForRow( + row: Row | undefined, + table: Table, + isLinked: boolean = false +): string { const primary = table.primary if (!row || !primary) { return "" @@ -151,7 +155,10 @@ function generateIdForRow(row: Row | undefined, table: Table): string { let idParts = [] for (let field of primary) { // need to handle table name + field or just field, depending on if relationships used - const fieldValue = row[`${table.name}.${field}`] || row[field] + let fieldValue = row[`${table.name}.${field}`] + if (!fieldValue && !isLinked) { + fieldValue = row[field] + } if (fieldValue) { idParts.push(fieldValue) } @@ -174,23 +181,20 @@ function getEndpoint(tableId: string | undefined, operation: string) { } } -function basicProcessing(row: Row, table: Table): Row { +function basicProcessing(row: Row, table: Table, isLinked: boolean): Row { const thisRow: Row = {} // filter the row down to what is actually the row (not joined) for (let field of Object.values(table.schema)) { const fieldName = field.name const pathValue = row[`${table.name}.${fieldName}`] - const value = - pathValue != null || field.type === FieldTypes.LINK - ? pathValue - : row[fieldName] + const value = pathValue != null || isLinked ? pathValue : row[fieldName] // all responses include "select col as table.col" so that overlaps are handled if (value != null) { thisRow[fieldName] = value } } - thisRow._id = generateIdForRow(row, table) + thisRow._id = generateIdForRow(row, table, isLinked) thisRow.tableId = table._id thisRow._rev = "rev" return processFormulas(table, thisRow) @@ -385,15 +389,7 @@ export class ExternalRequest { continue } - if ( - relationship.from && - row[fromColumn] === undefined && - row[relationship.from] === null - ) { - continue - } - - let linked = basicProcessing(row, linkedTable) + let linked = basicProcessing(row, linkedTable, true) if (!linked._id) { continue } @@ -441,7 +437,7 @@ export class ExternalRequest { ) continue } - const thisRow = fixArrayTypes(basicProcessing(row, table), table) + const thisRow = fixArrayTypes(basicProcessing(row, table, false), table) if (thisRow._id == null) { throw "Unable to generate row ID for SQL rows" } diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index c688600e8d..cc8760023f 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,11 +23,19 @@ jest.setTimeout(30000) jest.unmock("pg") +interface RandomForeignKeyConfig { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number +} + describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, primaryPostgresTable: Table, - auxPostgresTable: Table + o2mInfo: { table: Table; fieldName: string }, + m2oInfo: { table: Table; fieldName: string }, + m2mInfo: { table: Table; fieldName: string } let host: string let port: number @@ -67,31 +75,46 @@ describe("row api - postgres", () => { }, }) - auxPostgresTable = await config.createTable({ - name: generator.word({ length: 10 }), - type: "external", - primary: ["id"], - schema: { - id: { - name: "id", - type: FieldType.AUTO, - constraints: { - presence: true, + async function createAuxTable(prefix: string) { + return await config.createTable({ + name: `${prefix}_${generator.word({ length: 6 })}`, + type: "external", + primary: ["id"], + schema: { + id: { + name: "id", + type: FieldType.AUTO, + constraints: { + presence: true, + }, + }, + title: { + name: "title", + type: FieldType.STRING, + constraints: { + presence: true, + }, }, }, - title: { - name: "title", - type: FieldType.STRING, - constraints: { - presence: true, - }, - }, - }, - sourceId: postgresDatasource._id, - }) + sourceId: postgresDatasource._id, + }) + } + + o2mInfo = { + table: await createAuxTable("o2m"), + fieldName: "oneToManyRelation", + } + m2oInfo = { + table: await createAuxTable("m2o"), + fieldName: "manyToOneRelation", + } + m2mInfo = { + table: await createAuxTable("m2m"), + fieldName: "manyToManyRelation", + } primaryPostgresTable = await config.createTable({ - name: generator.word({ length: 10 }), + name: `p_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], schema: { @@ -117,25 +140,45 @@ describe("row api - postgres", () => { name: "value", type: FieldType.NUMBER, }, - linkedField: { + oneToManyRelation: { type: FieldType.LINK, constraints: { type: "array", presence: false, }, - fieldName: "foreignField", - name: "linkedField", + fieldName: o2mInfo.fieldName, + name: "oneToManyRelation", relationshipType: RelationshipTypes.ONE_TO_MANY, - tableId: auxPostgresTable._id, + tableId: o2mInfo.table._id, + }, + manyToOneRelation: { + type: FieldType.LINK, + constraints: { + type: "array", + presence: false, + }, + fieldName: m2oInfo.fieldName, + name: "manyToOneRelation", + relationshipType: RelationshipTypes.MANY_TO_ONE, + tableId: m2oInfo.table._id, + }, + manyToManyRelation: { + type: FieldType.LINK, + constraints: { + type: "array", + presence: false, + }, + fieldName: m2mInfo.fieldName, + name: "manyToManyRelation", + relationshipType: RelationshipTypes.MANY_TO_MANY, + tableId: m2mInfo.table._id, }, }, sourceId: postgresDatasource._id, }) }) - afterAll(async () => { - await config.end() - }) + afterAll(config.end) function generateRandomPrimaryRowData() { return { @@ -153,19 +196,20 @@ describe("row api - postgres", () => { async function createPrimaryRow(opts: { rowData: PrimaryRowData - createForeignRow?: boolean + createForeignRows?: RandomForeignKeyConfig }) { let { rowData } = opts let foreignRow: Row | undefined - if (opts?.createForeignRow) { + + if (opts?.createForeignRows?.createOne2Many) { foreignRow = await config.createRow({ - tableId: auxPostgresTable._id, + tableId: o2mInfo.table._id, title: generator.name(), }) rowData = { ...rowData, - [`fk_${auxPostgresTable.name}_foreignField`]: foreignRow.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, } } @@ -197,9 +241,7 @@ describe("row api - postgres", () => { async function populatePrimaryRows( count: number, - opts?: { - createForeignRow?: boolean - } + opts?: RandomForeignKeyConfig ) { return await Promise.all( Array(count) @@ -210,7 +252,7 @@ describe("row api - postgres", () => { rowData, ...(await createPrimaryRow({ rowData, - createForeignRow: opts?.createForeignRow, + createForeignRows: opts, })), } }) @@ -295,7 +337,7 @@ describe("row api - postgres", () => { describe("given than a row exists", () => { let row: Row beforeEach(async () => { - let rowResponse = _.sample(await populatePrimaryRows(10))! + let rowResponse = _.sample(await populatePrimaryRows(1))! row = rowResponse.row }) @@ -422,7 +464,7 @@ describe("row api - postgres", () => { let foreignRow: Row beforeEach(async () => { let [createdRow] = await populatePrimaryRows(1, { - createForeignRow: true, + createOne2Many: true, }) row = createdRow.row foreignRow = createdRow.foreignRow! @@ -437,16 +479,10 @@ describe("row api - postgres", () => { ...row, _id: expect.any(String), _rev: expect.any(String), + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, }) - expect(res.body.foreignField).toBeUndefined() - - expect( - res.body[`fk_${auxPostgresTable.name}_foreignField`] - ).toBeDefined() - expect(res.body[`fk_${auxPostgresTable.name}_foreignField`]).toBe( - foreignRow.id - ) + expect(res.body[o2mInfo.fieldName]).toBeUndefined() }) }) }) @@ -672,7 +708,7 @@ describe("row api - postgres", () => { beforeEach(async () => { const rowsInfo = await createPrimaryRow({ rowData: generateRandomPrimaryRowData(), - createForeignRow: true, + createForeignRows: { createOne2Many: true }, }) row = rowsInfo.row @@ -687,7 +723,7 @@ describe("row api - postgres", () => { expect(foreignRow).toBeDefined() expect(res.body).toEqual({ ...row, - linkedField: [ + [o2mInfo.fieldName]: [ { ...foreignRow, }, From 70689c03690ba9440df4c0f8bee3c0d7ceaa074d Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 00:06:57 +0100 Subject: [PATCH 108/273] Fix tests --- .../src/integration-test/postgres.spec.ts | 257 ++++++++++++++---- 1 file changed, 204 insertions(+), 53 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index cc8760023f..1707e596fd 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,19 +23,25 @@ jest.setTimeout(30000) jest.unmock("pg") -interface RandomForeignKeyConfig { - createOne2Many?: boolean - createMany2One?: number - createMany2Many?: number +interface ForeignTableInfo { + table: Table + fieldName: string + relationshipType: RelationshipTypes +} + +interface ForeignRowsInfo { + row: Row + foreignKey: string + relationshipType: RelationshipTypes } describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, primaryPostgresTable: Table, - o2mInfo: { table: Table; fieldName: string }, - m2oInfo: { table: Table; fieldName: string }, - m2mInfo: { table: Table; fieldName: string } + o2mInfo: ForeignTableInfo, + m2oInfo: ForeignTableInfo, + m2mInfo: ForeignTableInfo let host: string let port: number @@ -103,14 +109,17 @@ describe("row api - postgres", () => { o2mInfo = { table: await createAuxTable("o2m"), fieldName: "oneToManyRelation", + relationshipType: RelationshipTypes.ONE_TO_MANY, } m2oInfo = { table: await createAuxTable("m2o"), fieldName: "manyToOneRelation", + relationshipType: RelationshipTypes.MANY_TO_ONE, } m2mInfo = { table: await createAuxTable("m2m"), fieldName: "manyToManyRelation", + relationshipType: RelationshipTypes.MANY_TO_MANY, } primaryPostgresTable = await config.createTable({ @@ -196,21 +205,43 @@ describe("row api - postgres", () => { async function createPrimaryRow(opts: { rowData: PrimaryRowData - createForeignRows?: RandomForeignKeyConfig + createForeignRows?: { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number + } }) { let { rowData } = opts - let foreignRow: Row | undefined + let foreignRows: ForeignRowsInfo[] = [] - if (opts?.createForeignRows?.createOne2Many) { - foreignRow = await config.createRow({ - tableId: o2mInfo.table._id, + async function createForeignRow(tableInfo: ForeignTableInfo) { + const foreignRow = await config.createRow({ + tableId: tableInfo.table._id, title: generator.name(), }) + const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` rowData = { ...rowData, - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, + [foreignKey]: foreignRow.id, } + foreignRows.push({ + row: foreignRow, + foreignKey, + relationshipType: tableInfo.relationshipType, + }) + } + + if (opts?.createForeignRows?.createOne2Many) { + await createForeignRow(o2mInfo) + } + + for (let i = 0; i < (opts?.createForeignRows?.createMany2One || 0); i++) { + await createForeignRow(m2oInfo) + } + + for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { + await createForeignRow(m2mInfo) } const row = await config.createRow({ @@ -218,7 +249,7 @@ describe("row api - postgres", () => { ...rowData, }) - return { row, foreignRow } + return { row, foreignRows } } async function createDefaultPgTable() { @@ -241,7 +272,11 @@ describe("row api - postgres", () => { async function populatePrimaryRows( count: number, - opts?: RandomForeignKeyConfig + opts?: { + createOne2Many?: boolean + createMany2One?: number + createMany2Many?: number + } ) { return await Promise.all( Array(count) @@ -461,28 +496,134 @@ describe("row api - postgres", () => { describe("given a row with relation data", () => { let row: Row - let foreignRow: Row - beforeEach(async () => { - let [createdRow] = await populatePrimaryRows(1, { - createOne2Many: true, + let rowData: { + name: string + description: string + value: number + } + let foreignRows: ForeignRowsInfo[] + + describe("with all relationship types", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createOne2Many: true, + createMany2One: 3, + createMany2Many: 2, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + const one2ManyForeignRows = foreignRows.filter( + x => x.relationshipType === RelationshipTypes.ONE_TO_MANY + ) + expect(one2ManyForeignRows).toHaveLength(1) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + [one2ManyForeignRows[0].foreignKey]: one2ManyForeignRows[0].row.id, + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() }) - row = createdRow.row - foreignRow = createdRow.foreignRow! }) - it("only foreign keys are retrieved", async () => { - const res = await getRow(primaryPostgresTable._id, row.id) - - expect(res.status).toBe(200) - - expect(res.body).toEqual({ - ...row, - _id: expect.any(String), - _rev: expect.any(String), - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: foreignRow.id, + describe("with only one to many", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createOne2Many: true, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows }) - expect(res.body[o2mInfo.fieldName]).toBeUndefined() + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(1) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + [foreignRows[0].foreignKey]: foreignRows[0].row.id, + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) + }) + + describe("with only many to one", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createMany2One: 3, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(3) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) + }) + + describe("with only many to many", () => { + beforeEach(async () => { + let [createdRow] = await populatePrimaryRows(1, { + createMany2Many: 2, + }) + row = createdRow.row + rowData = createdRow.rowData + foreignRows = createdRow.foreignRows + }) + + it("only one to many foreign keys are retrieved", async () => { + const res = await getRow(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(foreignRows).toHaveLength(2) + + expect(res.body).toEqual({ + ...rowData, + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + + expect(res.body[o2mInfo.fieldName]).toBeUndefined() + }) }) }) }) @@ -703,31 +844,41 @@ describe("row api - postgres", () => { const getAll = (tableId: string | undefined, rowId: string | undefined) => makeRequest("get", `/api/${tableId}/${rowId}/enrich`) describe("given a row with relation data", () => { - let row: Row, foreignRow: Row | undefined + let row: Row, rowData: PrimaryRowData, foreignRows: ForeignRowsInfo[] - beforeEach(async () => { - const rowsInfo = await createPrimaryRow({ - rowData: generateRandomPrimaryRowData(), - createForeignRows: { createOne2Many: true }, + describe("only with one to many data", () => { + beforeEach(async () => { + rowData = generateRandomPrimaryRowData() + const rowsInfo = await createPrimaryRow({ + rowData, + createForeignRows: { createOne2Many: true }, + }) + + row = rowsInfo.row + foreignRows = rowsInfo.foreignRows }) - row = rowsInfo.row - foreignRow = rowsInfo.foreignRow - }) + it("enrich populates the foreign field", async () => { + const res = await getAll(primaryPostgresTable._id, row.id) - it("enrich populates the foreign field", async () => { - const res = await getAll(primaryPostgresTable._id, row.id) + expect(res.status).toBe(200) - expect(res.status).toBe(200) - - expect(foreignRow).toBeDefined() - expect(res.body).toEqual({ - ...row, - [o2mInfo.fieldName]: [ - { - ...foreignRow, - }, - ], + expect(foreignRows).toHaveLength(1) + expect(res.body).toEqual({ + ...rowData, + [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [o2mInfo.fieldName]: [ + { + ...foreignRows[0].row, + _id: expect.any(String), + _rev: expect.any(String), + }, + ], + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) }) }) }) @@ -750,7 +901,7 @@ describe("row api - postgres", () => { const rowsCount = 6 let rows: { row: Row - foreignRow: Row | undefined + foreignRows: ForeignRowsInfo[] rowData: PrimaryRowData }[] beforeEach(async () => { From 8047a0fc4cc5f7d198705ccc24554c551984b337 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 23 Feb 2023 08:09:18 +0000 Subject: [PATCH 109/273] Fix error being thrown when attempting to change query parameters (#9782) --- .../controls/ButtonActionEditor/actions/ExecuteQuery.svelte | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte index 840a639fb4..ba72fd2ed7 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte @@ -20,6 +20,12 @@ x => x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE ) + // Ensure query params exist so they can be bound + $: { + if (!parameters.queryParams) { + parameters.queryParams = {} + } + } function fetchQueryDefinition(query) { const source = $datasources.list.find( From 9e0d003038b594219abaa130d77807145541c47f Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:28:24 +0100 Subject: [PATCH 110/273] Fix creation --- packages/server/src/api/controllers/row/ExternalRequest.ts | 1 + packages/server/src/integrations/base/sql.ts | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 79a598edf0..74d48cb93e 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -741,6 +741,7 @@ export class ExternalRequest { table, }, } + // can't really use response right now const response = await getDatasourceAndQuery(json) // handle many to many relationships now if we know the ID (could be auto increment) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index c722891910..6871d7b0ba 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -415,9 +415,7 @@ class InternalBuilder { if (opts.disableReturning) { return query.insert(parsedBody) } else { - return query - .insert(parsedBody) - .returning(generateSelectStatement(json, knex)) + return query.insert(parsedBody).returning("*") } } From 7868fc657d5bf31c4cc7a9bef5eb2b77bfb2bf34 Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:39:16 +0100 Subject: [PATCH 111/273] Fix many-to-one tests --- .../src/integration-test/postgres.spec.ts | 115 +++++++++++++++--- 1 file changed, 95 insertions(+), 20 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 1707e596fd..b9f356ded1 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -23,18 +23,6 @@ jest.setTimeout(30000) jest.unmock("pg") -interface ForeignTableInfo { - table: Table - fieldName: string - relationshipType: RelationshipTypes -} - -interface ForeignRowsInfo { - row: Row - foreignKey: string - relationshipType: RelationshipTypes -} - describe("row api - postgres", () => { let makeRequest: MakeRequestResponse, postgresDatasource: Datasource, @@ -86,10 +74,12 @@ describe("row api - postgres", () => { name: `${prefix}_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], + primaryDisplay: "title", schema: { id: { name: "id", type: FieldType.AUTO, + autocolumn: true, constraints: { presence: true, }, @@ -130,6 +120,7 @@ describe("row api - postgres", () => { id: { name: "id", type: FieldType.AUTO, + autocolumn: true, constraints: { presence: true, }, @@ -159,6 +150,7 @@ describe("row api - postgres", () => { name: "oneToManyRelation", relationshipType: RelationshipTypes.ONE_TO_MANY, tableId: o2mInfo.table._id, + main: true, }, manyToOneRelation: { type: FieldType.LINK, @@ -170,6 +162,7 @@ describe("row api - postgres", () => { name: "manyToOneRelation", relationshipType: RelationshipTypes.MANY_TO_ONE, tableId: m2oInfo.table._id, + main: true, }, manyToManyRelation: { type: FieldType.LINK, @@ -181,6 +174,7 @@ describe("row api - postgres", () => { name: "manyToManyRelation", relationshipType: RelationshipTypes.MANY_TO_MANY, tableId: m2mInfo.table._id, + main: true, }, }, sourceId: postgresDatasource._id, @@ -203,6 +197,17 @@ describe("row api - postgres", () => { value: number } + type ForeignTableInfo = { + table: Table + fieldName: string + relationshipType: RelationshipTypes + } + + type ForeignRowsInfo = { + row: Row + relationshipType: RelationshipTypes + } + async function createPrimaryRow(opts: { rowData: PrimaryRowData createForeignRows?: { @@ -211,33 +216,61 @@ describe("row api - postgres", () => { createMany2Many?: number } }) { - let { rowData } = opts + let { rowData } = opts as any let foreignRows: ForeignRowsInfo[] = [] async function createForeignRow(tableInfo: ForeignTableInfo) { + const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` + const foreignRow = await config.createRow({ tableId: tableInfo.table._id, title: generator.name(), }) - const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` rowData = { ...rowData, [foreignKey]: foreignRow.id, } foreignRows.push({ row: foreignRow, - foreignKey, + relationshipType: tableInfo.relationshipType, }) } if (opts?.createForeignRows?.createOne2Many) { - await createForeignRow(o2mInfo) + const foreignKey = `fk_${o2mInfo.table.name}_${o2mInfo.fieldName}` + + const foreignRow = await config.createRow({ + tableId: o2mInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [foreignKey]: foreignRow.id, + } + foreignRows.push({ + row: foreignRow, + relationshipType: o2mInfo.relationshipType, + }) } for (let i = 0; i < (opts?.createForeignRows?.createMany2One || 0); i++) { - await createForeignRow(m2oInfo) + const foreignRow = await config.createRow({ + tableId: m2oInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [m2oInfo.fieldName]: rowData[m2oInfo.fieldName] || [], + } + rowData[m2oInfo.fieldName].push(foreignRow._id) + foreignRows.push({ + row: foreignRow, + relationshipType: RelationshipTypes.MANY_TO_ONE, + }) } for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { @@ -531,7 +564,8 @@ describe("row api - postgres", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), - [one2ManyForeignRows[0].foreignKey]: one2ManyForeignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + one2ManyForeignRows[0].row.id, }) expect(res.body[o2mInfo.fieldName]).toBeUndefined() @@ -561,7 +595,8 @@ describe("row api - postgres", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), - [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRows[0].row.id, }) expect(res.body[o2mInfo.fieldName]).toBeUndefined() @@ -866,7 +901,8 @@ describe("row api - postgres", () => { expect(foreignRows).toHaveLength(1) expect(res.body).toEqual({ ...rowData, - [foreignRows[0].foreignKey]: foreignRows[0].row.id, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRows[0].row.id, [o2mInfo.fieldName]: [ { ...foreignRows[0].row, @@ -881,6 +917,45 @@ describe("row api - postgres", () => { }) }) }) + + describe("only with many to one data", () => { + beforeEach(async () => { + rowData = generateRandomPrimaryRowData() + const rowsInfo = await createPrimaryRow({ + rowData, + createForeignRows: { + createMany2One: 2, + }, + }) + + row = rowsInfo.row + foreignRows = rowsInfo.foreignRows + }) + + it("enrich populates the foreign field", async () => { + const res = await getAll(primaryPostgresTable._id, row.id) + + expect(res.status).toBe(200) + + expect(res.body).toEqual({ + ...rowData, + [m2oInfo.fieldName]: [ + { + ...foreignRows[0].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + { + ...foreignRows[1].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + ], + id: row.id, + tableId: row.tableId, + _id: expect.any(String), + _rev: expect.any(String), + }) + }) + }) }) }) From 5207f5108035d01cfed3ab4f0f9d242d9149f8fa Mon Sep 17 00:00:00 2001 From: adrinr Date: Thu, 23 Feb 2023 10:50:18 +0100 Subject: [PATCH 112/273] Test enrich for all relationship types --- .../src/integration-test/postgres.spec.ts | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index b9f356ded1..df0e4bac15 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -274,7 +274,20 @@ describe("row api - postgres", () => { } for (let i = 0; i < (opts?.createForeignRows?.createMany2Many || 0); i++) { - await createForeignRow(m2mInfo) + const foreignRow = await config.createRow({ + tableId: m2mInfo.table._id, + title: generator.name(), + }) + + rowData = { + ...rowData, + [m2mInfo.fieldName]: rowData[m2mInfo.fieldName] || [], + } + rowData[m2mInfo.fieldName].push(foreignRow._id) + foreignRows.push({ + row: foreignRow, + relationshipType: RelationshipTypes.MANY_TO_MANY, + }) } const row = await config.createRow({ @@ -513,7 +526,7 @@ describe("row api - postgres", () => { let rows: { row: Row; rowData: PrimaryRowData }[] beforeEach(async () => { - rows = await populatePrimaryRows(10) + rows = await populatePrimaryRows(5) }) it("a single row can be retrieved successfully", async () => { @@ -881,50 +894,15 @@ describe("row api - postgres", () => { describe("given a row with relation data", () => { let row: Row, rowData: PrimaryRowData, foreignRows: ForeignRowsInfo[] - describe("only with one to many data", () => { - beforeEach(async () => { - rowData = generateRandomPrimaryRowData() - const rowsInfo = await createPrimaryRow({ - rowData, - createForeignRows: { createOne2Many: true }, - }) - - row = rowsInfo.row - foreignRows = rowsInfo.foreignRows - }) - - it("enrich populates the foreign field", async () => { - const res = await getAll(primaryPostgresTable._id, row.id) - - expect(res.status).toBe(200) - - expect(foreignRows).toHaveLength(1) - expect(res.body).toEqual({ - ...rowData, - [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: - foreignRows[0].row.id, - [o2mInfo.fieldName]: [ - { - ...foreignRows[0].row, - _id: expect.any(String), - _rev: expect.any(String), - }, - ], - id: row.id, - tableId: row.tableId, - _id: expect.any(String), - _rev: expect.any(String), - }) - }) - }) - - describe("only with many to one data", () => { + describe("with all relationship types", () => { beforeEach(async () => { rowData = generateRandomPrimaryRowData() const rowsInfo = await createPrimaryRow({ rowData, createForeignRows: { - createMany2One: 2, + createOne2Many: true, + createMany2One: 3, + createMany2Many: 2, }, }) @@ -932,22 +910,47 @@ describe("row api - postgres", () => { foreignRows = rowsInfo.foreignRows }) - it("enrich populates the foreign field", async () => { + it("enrich populates the foreign fields", async () => { const res = await getAll(primaryPostgresTable._id, row.id) expect(res.status).toBe(200) + const foreignRowsByType = _.groupBy( + foreignRows, + x => x.relationshipType + ) expect(res.body).toEqual({ ...rowData, + [`fk_${o2mInfo.table.name}_${o2mInfo.fieldName}`]: + foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row.id, + [o2mInfo.fieldName]: [ + { + ...foreignRowsByType[RelationshipTypes.ONE_TO_MANY][0].row, + _id: expect.any(String), + _rev: expect.any(String), + }, + ], [m2oInfo.fieldName]: [ { - ...foreignRows[0].row, + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][0].row, [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, }, { - ...foreignRows[1].row, + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][1].row, [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, }, + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_ONE][2].row, + [`fk_${m2oInfo.table.name}_${m2oInfo.fieldName}`]: row.id, + }, + ], + [m2mInfo.fieldName]: [ + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][0].row, + }, + { + ...foreignRowsByType[RelationshipTypes.MANY_TO_MANY][1].row, + }, ], id: row.id, tableId: row.tableId, From b4c88bd545b1edea79f95deded40b35ae96c86e1 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 23 Feb 2023 10:38:03 +0000 Subject: [PATCH 113/273] Merge commit to dev --- packages/types/src/api/web/user.ts | 1 + .../src/api/controllers/global/users.ts | 119 +++++++++++++++++- packages/worker/src/sdk/users/users.ts | 6 +- packages/worker/src/utilities/redis.ts | 40 ++++++ 4 files changed, 159 insertions(+), 7 deletions(-) diff --git a/packages/types/src/api/web/user.ts b/packages/types/src/api/web/user.ts index 6acaf6912d..18f98048c4 100644 --- a/packages/types/src/api/web/user.ts +++ b/packages/types/src/api/web/user.ts @@ -16,6 +16,7 @@ export interface BulkUserRequest { userIds: string[] } create?: { + roles?: any[] users: User[] groups: any[] } diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index 817480151d..f8cb4b2103 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -1,4 +1,8 @@ -import { checkInviteCode } from "../../../utilities/redis" +import { + checkInviteCode, + getInviteCodes, + updateInviteCode, +} from "../../../utilities/redis" import sdk from "../../../sdk" import env from "../../../environment" import { @@ -6,7 +10,6 @@ import { BulkUserResponse, CloudAccount, CreateAdminUserRequest, - InviteUserRequest, InviteUsersRequest, SearchUsersRequest, User, @@ -19,6 +22,7 @@ import { tenancy, } from "@budibase/backend-core" import { checkAnyUserExists } from "../../../utilities/users" +import { isEmailConfigured } from "src/utilities/email" const MAX_USERS_UPLOAD_LIMIT = 1000 @@ -186,9 +190,54 @@ export const tenantUserLookup = async (ctx: any) => { } } +/* + Encapsulate the app user onboarding flows here. +*/ +export const onboardUsers = async (ctx: any) => { + const request = ctx.request.body as InviteUsersRequest | BulkUserRequest + const isBulkCreate = "create" in request + + const emailConfigured = await isEmailConfigured() + + let onboardingResponse + + if (isBulkCreate) { + // @ts-ignore + const { users, groups, roles } = request.create + const assignUsers = users.map((user: User) => (user.roles = roles)) + onboardingResponse = await sdk.users.bulkCreate(assignUsers, groups) + ctx.body = onboardingResponse + } else if (emailConfigured) { + onboardingResponse = await invite(ctx) + } else if (!emailConfigured) { + const inviteRequest = ctx.request.body as InviteUsersRequest + const users: User[] = inviteRequest.map(invite => { + let password = Math.random().toString(36).substring(2, 22) + + return { + email: invite.email, + password, + forceResetPassword: true, + roles: invite.userInfo.apps, + admin: { global: false }, + builder: { global: false }, + tenantId: tenancy.getTenantId(), + } + }) + let bulkCreateReponse = await sdk.users.bulkCreate(users, []) + onboardingResponse = { + ...bulkCreateReponse, + created: true, + } + ctx.body = onboardingResponse + } else { + ctx.throw(400, "User onboarding failed") + } +} + export const invite = async (ctx: any) => { - const request = ctx.request.body as InviteUserRequest - const response = await sdk.users.invite([request]) + const request = ctx.request.body as InviteUsersRequest + const response = await sdk.users.invite(request) // explicitly throw for single user invite if (response.unsuccessful.length) { @@ -202,6 +251,8 @@ export const invite = async (ctx: any) => { ctx.body = { message: "Invitation has been sent.", + successful: response.successful, + unsuccessful: response.unsuccessful, } } @@ -223,19 +274,75 @@ export const checkInvite = async (ctx: any) => { } } +export const getUserInvites = async (ctx: any) => { + let invites + try { + // Restricted to the currently authenticated tenant + invites = await getInviteCodes([ctx.user.tenantId]) + } catch (e) { + ctx.throw(400, "There was a problem fetching invites") + } + ctx.body = invites +} + +export const updateInvite = async (ctx: any) => { + const { code } = ctx.params + let updateBody = { ...ctx.request.body } + + delete updateBody.email + + let invite + try { + invite = await checkInviteCode(code, false) + if (!invite) { + throw new Error("The invite could not be retrieved") + } + } catch (e) { + ctx.throw(400, "There was a problem with the invite") + } + + let updated = { + ...invite, + } + + if (!updateBody?.apps || !Object.keys(updateBody?.apps).length) { + updated.info.apps = [] + } else { + updated.info = { + ...invite.info, + apps: { + ...invite.info.apps, + ...updateBody.apps, + }, + } + } + + await updateInviteCode(code, updated) + ctx.body = { ...invite } +} + export const inviteAccept = async (ctx: any) => { const { inviteCode, password, firstName, lastName } = ctx.request.body try { // info is an extension of the user object that was stored by global const { email, info }: any = await checkInviteCode(inviteCode) ctx.body = await tenancy.doInTenant(info.tenantId, async () => { - const saved = await sdk.users.save({ + let request = { firstName, lastName, password, email, + roles: info.apps, + } + + delete info.apps + + request = { + ...request, ...info, - }) + } + + const saved = await sdk.users.save(request) const db = tenancy.getGlobalDB() const user = await db.get(saved._id) await events.user.inviteAccepted(user) diff --git a/packages/worker/src/sdk/users/users.ts b/packages/worker/src/sdk/users/users.ts index 5124a5c5b1..db49e801c3 100644 --- a/packages/worker/src/sdk/users/users.ts +++ b/packages/worker/src/sdk/users/users.ts @@ -203,7 +203,7 @@ export const save = async ( const tenantId = tenancy.getTenantId() const db = tenancy.getGlobalDB() - let { email, _id, userGroups = [] } = user + let { email, _id, userGroups = [], roles } = user if (!email && !_id) { throw new Error("_id or email is required") @@ -245,6 +245,10 @@ export const save = async ( builtUser.roles = dbUser.roles } + if (!dbUser && roles?.length) { + builtUser.roles = { ...roles } + } + // make sure we set the _id field for a new user // Also if this is a new user, associate groups with them let groupPromises = [] diff --git a/packages/worker/src/utilities/redis.ts b/packages/worker/src/utilities/redis.ts index 893ec9f0a8..a05b043054 100644 --- a/packages/worker/src/utilities/redis.ts +++ b/packages/worker/src/utilities/redis.ts @@ -29,6 +29,20 @@ async function writeACode(db: string, value: any) { return code } +async function updateACode(db: string, code: string, value: any) { + const client = await getClient(db) + await client.store(code, value, getExpirySecondsForDB(db)) +} + +/** + * Given an invite code and invite body, allow the update an existing/valid invite in redis + * @param {string} inviteCode The invite code for an invite in redis + * @param {object} value The body of the updated user invitation + */ +export async function updateInviteCode(inviteCode: string, value: string) { + await updateACode(redis.utils.Databases.INVITATIONS, inviteCode, value) +} + async function getACode(db: string, code: string, deleteCode = true) { const client = await getClient(db) const value = await client.get(code) @@ -111,3 +125,29 @@ export async function checkInviteCode( throw "Invitation is not valid or has expired, please request a new one." } } + +/** + Get all currently available user invitations. + @return {Object[]} A +**/ +export async function getInviteCodes( + tenantIds?: string[] //should default to the current tenant of the user session. +) { + const client = await getClient(redis.utils.Databases.INVITATIONS) + const invites: any[] = await client.scan() + + const results = invites.map(invite => { + return { + ...invite.value, + code: invite.key, + } + }) + return results.reduce((acc, invite) => { + if (tenantIds?.length && tenantIds.includes(invite.info.tenantId)) { + acc.push(invite) + } else { + acc.push(invite) + } + return acc + }, []) +} From 6efb0f4997986a419952996c0f1edd8e42c4a6c8 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Thu, 23 Feb 2023 10:57:50 +0000 Subject: [PATCH 114/273] update table width --- .../builder/portal/account/auditLogs/index.svelte | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte index 944ed87d1a..34c50f3354 100644 --- a/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte +++ b/packages/builder/src/pages/builder/portal/account/auditLogs/index.svelte @@ -1,3 +1,7 @@ + - + onMount(() => { + document.addEventListener("keydown", handleKey) + return () => { + document.removeEventListener("keydown", handleKey) + } + }) + {#if inline} {#if visible} diff --git a/packages/bbui/src/helpers.js b/packages/bbui/src/helpers.js index b02783e0bd..f2246fbb49 100644 --- a/packages/bbui/src/helpers.js +++ b/packages/bbui/src/helpers.js @@ -104,6 +104,9 @@ export const deepSet = (obj, key, value) => { * @param obj the object to clone */ export const cloneDeep = obj => { + if (!obj) { + return obj + } return JSON.parse(JSON.stringify(obj)) } diff --git a/packages/builder/package.json b/packages/builder/package.json index 3f4b4fb274..b87cd3924b 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -72,6 +72,7 @@ "codemirror": "^5.59.0", "dayjs": "^1.11.2", "downloadjs": "1.4.7", + "fast-json-patch": "^3.1.1", "lodash": "4.17.21", "posthog-js": "^1.36.0", "remixicon": "2.5.0", diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 69bca7eac3..d15cdb6e98 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -5,12 +5,47 @@ import { getThemeStore } from "./store/theme" import { derived } from "svelte/store" import { findComponent, findComponentPath } from "./componentUtils" import { RoleUtils } from "@budibase/frontend-core" +import { createHistoryStore } from "builderStore/store/history" +import { get } from "svelte/store" export const store = getFrontendStore() export const automationStore = getAutomationStore() export const themeStore = getThemeStore() export const temporalStore = getTemporalStore() +// Setup history for screens +export const screenHistoryStore = createHistoryStore({ + getDoc: id => get(store).screens?.find(screen => screen._id === id), + selectDoc: store.actions.screens.select, + afterAction: () => { + // Ensure a valid component is selected + if (!get(selectedComponent)) { + store.update(state => ({ + ...state, + selectedComponentId: get(selectedScreen)?.props._id, + })) + } + }, +}) +store.actions.screens.save = screenHistoryStore.wrapSaveDoc( + store.actions.screens.save +) +store.actions.screens.delete = screenHistoryStore.wrapDeleteDoc( + store.actions.screens.delete +) + +// Setup history for automations +export const automationHistoryStore = createHistoryStore({ + getDoc: automationStore.actions.getDefinition, + selectDoc: automationStore.actions.select, +}) +automationStore.actions.save = automationHistoryStore.wrapSaveDoc( + automationStore.actions.save +) +automationStore.actions.delete = automationHistoryStore.wrapDeleteDoc( + automationStore.actions.delete +) + export const selectedScreen = derived(store, $store => { return $store.screens.find(screen => screen._id === $store.selectedScreenId) }) @@ -71,3 +106,13 @@ export const selectedComponentPath = derived( ).map(component => component._id) } ) + +// Derived automation state +export const selectedAutomation = derived(automationStore, $automationStore => { + if (!$automationStore.selectedAutomationId) { + return null + } + return $automationStore.automations?.find( + x => x._id === $automationStore.selectedAutomationId + ) +}) diff --git a/packages/builder/src/builderStore/store/automation/Automation.js b/packages/builder/src/builderStore/store/automation/Automation.js deleted file mode 100644 index af0c03cb5a..0000000000 --- a/packages/builder/src/builderStore/store/automation/Automation.js +++ /dev/null @@ -1,69 +0,0 @@ -import { generate } from "shortid" - -/** - * Class responsible for the traversing of the automation definition. - * Automation definitions are stored in linked lists. - */ -export default class Automation { - constructor(automation) { - this.automation = automation - } - - hasTrigger() { - return this.automation.definition.trigger - } - - addTestData(data) { - this.automation.testData = { ...this.automation.testData, ...data } - } - - addBlock(block, idx) { - // Make sure to add trigger if doesn't exist - if (!this.hasTrigger() && block.type === "TRIGGER") { - const trigger = { id: generate(), ...block } - this.automation.definition.trigger = trigger - return trigger - } - - const newBlock = { id: generate(), ...block } - this.automation.definition.steps.splice(idx, 0, newBlock) - return newBlock - } - - updateBlock(updatedBlock, id) { - const { steps, trigger } = this.automation.definition - - if (trigger && trigger.id === id) { - this.automation.definition.trigger = updatedBlock - return - } - - const stepIdx = steps.findIndex(step => step.id === id) - if (stepIdx < 0) throw new Error("Block not found.") - steps.splice(stepIdx, 1, updatedBlock) - this.automation.definition.steps = steps - } - - deleteBlock(id) { - const { steps, trigger } = this.automation.definition - - if (trigger && trigger.id === id) { - this.automation.definition.trigger = null - return - } - - const stepIdx = steps.findIndex(step => step.id === id) - if (stepIdx < 0) throw new Error("Block not found.") - steps.splice(stepIdx, 1) - this.automation.definition.steps = steps - } - - constructBlock(type, stepId, blockDefinition) { - return { - ...blockDefinition, - inputs: blockDefinition.inputs || {}, - stepId, - type, - } - } -} diff --git a/packages/builder/src/builderStore/store/automation/index.js b/packages/builder/src/builderStore/store/automation/index.js index af102ab694..dc1e2a2cc1 100644 --- a/packages/builder/src/builderStore/store/automation/index.js +++ b/packages/builder/src/builderStore/store/automation/index.js @@ -1,16 +1,18 @@ -import { writable } from "svelte/store" +import { writable, get } from "svelte/store" import { API } from "api" -import Automation from "./Automation" import { cloneDeep } from "lodash/fp" +import { generate } from "shortid" +import { selectedAutomation } from "builderStore" const initialAutomationState = { automations: [], + testResults: null, showTestPanel: false, blockDefinitions: { TRIGGER: [], ACTION: [], }, - selectedAutomation: null, + selectedAutomationId: null, } export const getAutomationStore = () => { @@ -37,49 +39,41 @@ const automationActions = store => ({ API.getAutomationDefinitions(), ]) store.update(state => { - let selected = state.selectedAutomation?.automation state.automations = responses[0] + state.automations.sort((a, b) => { + return a.name < b.name ? -1 : 1 + }) state.blockDefinitions = { TRIGGER: responses[1].trigger, ACTION: responses[1].action, } - // If previously selected find the new obj and select it - if (selected) { - selected = responses[0].filter( - automation => automation._id === selected._id - ) - state.selectedAutomation = new Automation(selected[0]) - } return state }) }, - create: async ({ name }) => { + create: async (name, trigger) => { const automation = { name, type: "automation", definition: { steps: [], + trigger, }, } - const response = await API.createAutomation(automation) - store.update(state => { - state.automations = [...state.automations, response.automation] - store.actions.select(response.automation) - return state - }) + const response = await store.actions.save(automation) + await store.actions.fetch() + store.actions.select(response._id) + return response }, duplicate: async automation => { - const response = await API.createAutomation({ + const response = await store.actions.save({ ...automation, name: `${automation.name} - copy`, _id: undefined, _ref: undefined, }) - store.update(state => { - state.automations = [...state.automations, response.automation] - store.actions.select(response.automation) - return state - }) + await store.actions.fetch() + store.actions.select(response._id) + return response }, save: async automation => { const response = await API.updateAutomation(automation) @@ -90,11 +84,13 @@ const automationActions = store => ({ ) if (existingIdx !== -1) { state.automations.splice(existingIdx, 1, updatedAutomation) - state.automations = [...state.automations] - store.actions.select(updatedAutomation) return state + } else { + state.automations = [...state.automations, updatedAutomation] } + return state }) + return response.automation }, delete: async automation => { await API.deleteAutomation({ @@ -102,34 +98,83 @@ const automationActions = store => ({ automationRev: automation?._rev, }) store.update(state => { - const existingIdx = state.automations.findIndex( - existing => existing._id === automation?._id + // Remove the automation + state.automations = state.automations.filter( + x => x._id !== automation._id ) - state.automations.splice(existingIdx, 1) - state.automations = [...state.automations] - state.selectedAutomation = null - state.selectedBlock = null + // Select a new automation if required + if (automation._id === state.selectedAutomationId) { + store.actions.select(state.automations[0]?._id) + } return state }) + await store.actions.fetch() + }, + updateBlockInputs: async (block, data) => { + // Create new modified block + let newBlock = { + ...block, + inputs: { + ...block.inputs, + ...data, + }, + } + + // Remove any nullish or empty string values + Object.keys(newBlock.inputs).forEach(key => { + const val = newBlock.inputs[key] + if (val == null || val === "") { + delete newBlock.inputs[key] + } + }) + + // Create new modified automation + const automation = get(selectedAutomation) + const newAutomation = store.actions.getUpdatedDefinition( + automation, + newBlock + ) + + // Don't save if no changes were made + if (JSON.stringify(newAutomation) === JSON.stringify(automation)) { + return + } + await store.actions.save(newAutomation) }, test: async (automation, testData) => { - store.update(state => { - state.selectedAutomation.testResults = null - return state - }) const result = await API.testAutomation({ automationId: automation?._id, testData, }) + if (!result?.trigger && !result?.steps?.length) { + throw "Something went wrong testing your automation" + } store.update(state => { - state.selectedAutomation.testResults = result + state.testResults = result return state }) }, - select: automation => { + getDefinition: id => { + return get(store).automations?.find(x => x._id === id) + }, + getUpdatedDefinition: (automation, block) => { + let newAutomation = cloneDeep(automation) + if (automation.definition.trigger?.id === block.id) { + newAutomation.definition.trigger = block + } else { + const idx = automation.definition.steps.findIndex(x => x.id === block.id) + newAutomation.definition.steps.splice(idx, 1, block) + } + return newAutomation + }, + select: id => { + if (!id || id === get(store).selectedAutomationId) { + return + } store.update(state => { - state.selectedAutomation = new Automation(cloneDeep(automation)) - state.selectedBlock = null + state.selectedAutomationId = id + state.testResults = null + state.showTestPanel = false return state }) }, @@ -147,48 +192,57 @@ const automationActions = store => ({ appId, }) }, - addTestDataToAutomation: data => { - store.update(state => { - state.selectedAutomation.addTestData(data) - return state - }) + addTestDataToAutomation: async data => { + let newAutomation = cloneDeep(get(selectedAutomation)) + newAutomation.testData = { + ...newAutomation.testData, + ...data, + } + await store.actions.save(newAutomation) }, - addBlockToAutomation: (block, blockIdx) => { - store.update(state => { - state.selectedBlock = state.selectedAutomation.addBlock( - cloneDeep(block), - blockIdx - ) - return state - }) + constructBlock(type, stepId, blockDefinition) { + return { + ...blockDefinition, + inputs: blockDefinition.inputs || {}, + stepId, + type, + id: generate(), + } }, - toggleFieldControl: value => { - store.update(state => { - state.selectedBlock.rowControl = value - return state - }) + addBlockToAutomation: async (block, blockIdx) => { + const automation = get(selectedAutomation) + let newAutomation = cloneDeep(automation) + if (!automation) { + return + } + newAutomation.definition.steps.splice(blockIdx, 0, block) + await store.actions.save(newAutomation) }, - deleteAutomationBlock: block => { - store.update(state => { - const idx = - state.selectedAutomation.automation.definition.steps.findIndex( - x => x.id === block.id - ) - state.selectedAutomation.deleteBlock(block.id) + /** + * "rowControl" appears to be the name of the flag used to determine whether + * a certain automation block uses values or bindings as inputs + */ + toggleRowControl: async (block, rowControl) => { + const newBlock = { ...block, rowControl } + const newAutomation = store.actions.getUpdatedDefinition( + get(selectedAutomation), + newBlock + ) + await store.actions.save(newAutomation) + }, + deleteAutomationBlock: async block => { + const automation = get(selectedAutomation) + let newAutomation = cloneDeep(automation) - // Select next closest step - const steps = state.selectedAutomation.automation.definition.steps - let nextSelectedBlock - if (steps[idx] != null) { - nextSelectedBlock = steps[idx] - } else if (steps[idx - 1] != null) { - nextSelectedBlock = steps[idx - 1] - } else { - nextSelectedBlock = - state.selectedAutomation.automation.definition.trigger || null - } - state.selectedBlock = nextSelectedBlock - return state - }) + // Delete trigger if required + if (newAutomation.definition.trigger?.id === block.id) { + delete newAutomation.definition.trigger + } else { + // Otherwise remove step + newAutomation.definition.steps = newAutomation.definition.steps.filter( + step => step.id !== block.id + ) + } + await store.actions.save(newAutomation) }, }) diff --git a/packages/builder/src/builderStore/store/automation/tests/Automation.spec.js b/packages/builder/src/builderStore/store/automation/tests/Automation.spec.js deleted file mode 100644 index 8378310c2e..0000000000 --- a/packages/builder/src/builderStore/store/automation/tests/Automation.spec.js +++ /dev/null @@ -1,48 +0,0 @@ -import Automation from "../Automation" -import TEST_AUTOMATION from "./testAutomation" - -const TEST_BLOCK = { - id: "AUXJQGZY7", - name: "Delay", - icon: "ri-time-fill", - tagline: "Delay for {{time}} milliseconds", - description: "Delay the automation until an amount of time has passed.", - params: { time: "number" }, - type: "LOGIC", - args: { time: "5000" }, - stepId: "DELAY", -} - -describe("Automation Data Object", () => { - let automation - - beforeEach(() => { - automation = new Automation({ ...TEST_AUTOMATION }) - }) - - it("adds a automation block to the automation", () => { - automation.addBlock(TEST_BLOCK) - expect(automation.automation.definition) - }) - - it("updates a automation block with new attributes", () => { - const firstBlock = automation.automation.definition.steps[0] - const updatedBlock = { - ...firstBlock, - name: "UPDATED", - } - automation.updateBlock(updatedBlock, firstBlock.id) - expect(automation.automation.definition.steps[0]).toEqual(updatedBlock) - }) - - it("deletes a automation block successfully", () => { - const { steps } = automation.automation.definition - const originalLength = steps.length - - const lastBlock = steps[steps.length - 1] - automation.deleteBlock(lastBlock.id) - expect(automation.automation.definition.steps.length).toBeLessThan( - originalLength - ) - }) -}) diff --git a/packages/builder/src/builderStore/store/automation/tests/testAutomation.js b/packages/builder/src/builderStore/store/automation/tests/testAutomation.js deleted file mode 100644 index 3fafbaf1d0..0000000000 --- a/packages/builder/src/builderStore/store/automation/tests/testAutomation.js +++ /dev/null @@ -1,78 +0,0 @@ -export default { - name: "Test automation", - definition: { - steps: [ - { - id: "ANBDINAPS", - description: "Send an email.", - tagline: "Send email to {{to}}", - icon: "ri-mail-open-fill", - name: "Send Email", - params: { - to: "string", - from: "string", - subject: "longText", - text: "longText", - }, - type: "ACTION", - args: { - text: "A user was created!", - subject: "New Budibase User", - from: "budimaster@budibase.com", - to: "test@test.com", - }, - stepId: "SEND_EMAIL", - }, - ], - trigger: { - id: "iRzYMOqND", - name: "Row Saved", - event: "row:save", - icon: "ri-save-line", - tagline: "Row is added to {{table.name}}", - description: "Fired when a row is saved to your database.", - params: { table: "table" }, - type: "TRIGGER", - args: { - table: { - type: "table", - views: {}, - name: "users", - schema: { - name: { - type: "string", - constraints: { - type: "string", - length: { maximum: 123 }, - presence: { allowEmpty: false }, - }, - name: "name", - }, - age: { - type: "number", - constraints: { - type: "number", - presence: { allowEmpty: false }, - numericality: { - greaterThanOrEqualTo: "", - lessThanOrEqualTo: "", - }, - }, - name: "age", - }, - }, - _id: "c6b4e610cd984b588837bca27188a451", - _rev: "7-b8aa1ce0b53e88928bb88fc11bdc0aff", - }, - }, - stepId: "ROW_SAVED", - }, - }, - type: "automation", - ok: true, - id: "b384f861f4754e1693835324a7fcca62", - rev: "1-aa1c2cbd868ef02e26f8fad531dd7e37", - live: false, - _id: "b384f861f4754e1693835324a7fcca62", - _rev: "108-4116829ec375e0481d0ecab9e83a2caf", -} diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 56b8a599f0..d58a2d5b9e 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -1,6 +1,11 @@ import { get, writable } from "svelte/store" import { cloneDeep } from "lodash/fp" -import { selectedScreen, selectedComponent } from "builderStore" +import { + selectedScreen, + selectedComponent, + screenHistoryStore, + automationHistoryStore, +} from "builderStore" import { datasources, integrations, @@ -122,6 +127,8 @@ export const getFrontendStore = () => { navigation: application.navigation || {}, usedPlugins: application.usedPlugins || [], })) + screenHistoryStore.reset() + automationHistoryStore.reset() // Initialise backend stores database.set(application.instance) @@ -179,10 +186,7 @@ export const getFrontendStore = () => { } // Check screen isn't already selected - if ( - state.selectedScreenId === screen._id && - state.selectedComponentId === screen.props?._id - ) { + if (state.selectedScreenId === screen._id) { return } @@ -256,7 +260,7 @@ export const getFrontendStore = () => { } }, save: async screen => { - /* + /* Temporarily disabled to accomodate migration issues. store.actions.screens.validate(screen) */ @@ -347,6 +351,7 @@ export const getFrontendStore = () => { return state }) + return null }, updateSetting: async (screen, name, value) => { if (!screen || !name) { diff --git a/packages/builder/src/builderStore/store/history.js b/packages/builder/src/builderStore/store/history.js new file mode 100644 index 0000000000..0f21085c6a --- /dev/null +++ b/packages/builder/src/builderStore/store/history.js @@ -0,0 +1,319 @@ +import * as jsonpatch from "fast-json-patch/index.mjs" +import { writable, derived, get } from "svelte/store" + +const Operations = { + Add: "Add", + Delete: "Delete", + Change: "Change", +} + +const initialState = { + history: [], + position: 0, + loading: false, +} + +export const createHistoryStore = ({ + getDoc, + selectDoc, + beforeAction, + afterAction, +}) => { + // Use a derived store to check if we are able to undo or redo any operations + const store = writable(initialState) + const derivedStore = derived(store, $store => { + return { + ...$store, + canUndo: $store.position > 0, + canRedo: $store.position < $store.history.length, + } + }) + + // Wrapped versions of essential functions which we call ourselves when using + // undo and redo + let saveFn + let deleteFn + + /** + * Internal util to set the loading flag + */ + const startLoading = () => { + store.update(state => { + state.loading = true + return state + }) + } + + /** + * Internal util to unset the loading flag + */ + const stopLoading = () => { + store.update(state => { + state.loading = false + return state + }) + } + + /** + * Resets history state + */ + const reset = () => { + store.set(initialState) + } + + /** + * Adds or updates an operation in history. + * For internal use only. + * @param operation the operation to save + */ + const saveOperation = operation => { + store.update(state => { + // Update history + let history = state.history + let position = state.position + if (!operation.id) { + // Every time a new operation occurs we discard any redo potential + operation.id = Math.random() + history = [...history.slice(0, state.position), operation] + position += 1 + } else { + // If this is a redo/undo of an existing operation, just update history + // to replace the doc object as revisions may have changed + const idx = history.findIndex(op => op.id === operation.id) + history[idx].doc = operation.doc + } + return { history, position } + }) + } + + /** + * Wraps the save function, which asynchronously updates a doc. + * The returned function is an enriched version of the real save function so + * that we can control history. + * @param fn the save function + * @returns {function} a wrapped version of the save function + */ + const wrapSaveDoc = fn => { + saveFn = async (doc, operationId) => { + // Only works on a single doc at a time + if (!doc || Array.isArray(doc)) { + return + } + startLoading() + try { + const oldDoc = getDoc(doc._id) + const newDoc = jsonpatch.deepClone(await fn(doc)) + + // Store the change + if (!oldDoc) { + // If no old doc, this is an add operation + saveOperation({ + type: Operations.Add, + doc: newDoc, + id: operationId, + }) + } else { + // Otherwise this is a change operation + saveOperation({ + type: Operations.Change, + forwardPatch: jsonpatch.compare(oldDoc, doc), + backwardsPatch: jsonpatch.compare(doc, oldDoc), + doc: newDoc, + id: operationId, + }) + } + stopLoading() + return newDoc + } catch (error) { + // We want to allow errors to propagate up to normal handlers, but we + // want to stop loading first + stopLoading() + throw error + } + } + return saveFn + } + + /** + * Wraps the delete function, which asynchronously deletes a doc. + * The returned function is an enriched version of the real delete function so + * that we can control history. + * @param fn the delete function + * @returns {function} a wrapped version of the delete function + */ + const wrapDeleteDoc = fn => { + deleteFn = async (doc, operationId) => { + // Only works on a single doc at a time + if (!doc || Array.isArray(doc)) { + return + } + startLoading() + try { + const oldDoc = jsonpatch.deepClone(doc) + await fn(doc) + saveOperation({ + type: Operations.Delete, + doc: oldDoc, + id: operationId, + }) + stopLoading() + } catch (error) { + // We want to allow errors to propagate up to normal handlers, but we + // want to stop loading first + stopLoading() + throw error + } + } + return deleteFn + } + + /** + * Asynchronously undoes the previous operation. + * Optionally selects the changed document so that changes are visible. + * @returns {Promise} + */ + const undo = async () => { + // Sanity checks + const { canUndo, history, position, loading } = get(derivedStore) + if (!canUndo || loading) { + return + } + const operation = history[position - 1] + if (!operation) { + return + } + startLoading() + + // Before hook + await beforeAction?.(operation) + + // Update state immediately to prevent further clicks and to prevent bad + // history in the event of an update failing + store.update(state => { + return { + ...state, + position: state.position - 1, + } + }) + + // Undo the operation + try { + // Undo ADD + if (operation.type === Operations.Add) { + // Try to get the latest doc version to delete + const latestDoc = getDoc(operation.doc._id) + const doc = latestDoc || operation.doc + await deleteFn(doc, operation.id) + } + + // Undo DELETE + else if (operation.type === Operations.Delete) { + // Delete the _rev from the deleted doc so that we can save it as a new + // doc again without conflicts + let doc = jsonpatch.deepClone(operation.doc) + delete doc._rev + const created = await saveFn(doc, operation.id) + selectDoc?.(created?._id || doc._id) + } + + // Undo CHANGE + else { + // Get the current doc and apply the backwards patch on top of it + let doc = jsonpatch.deepClone(getDoc(operation.doc._id)) + if (doc) { + jsonpatch.applyPatch( + doc, + jsonpatch.deepClone(operation.backwardsPatch) + ) + await saveFn(doc, operation.id) + selectDoc?.(doc._id) + } + } + stopLoading() + } catch (error) { + stopLoading() + throw error + } + + // After hook + await afterAction?.(operation) + } + + /** + * Asynchronously redoes the previous undo. + * Optionally selects the changed document so that changes are visible. + * @returns {Promise} + */ + const redo = async () => { + // Sanity checks + const { canRedo, history, position, loading } = get(derivedStore) + if (!canRedo || loading) { + return + } + const operation = history[position] + if (!operation) { + return + } + startLoading() + + // Before hook + await beforeAction?.(operation) + + // Update state immediately to prevent further clicks and to prevent bad + // history in the event of an update failing + store.update(state => { + return { + ...state, + position: state.position + 1, + } + }) + + // Redo the operation + try { + // Redo ADD + if (operation.type === Operations.Add) { + // Delete the _rev from the deleted doc so that we can save it as a new + // doc again without conflicts + let doc = jsonpatch.deepClone(operation.doc) + delete doc._rev + const created = await saveFn(doc, operation.id) + selectDoc?.(created?._id || doc._id) + } + + // Redo DELETE + else if (operation.type === Operations.Delete) { + // Try to get the latest doc version to delete + const latestDoc = getDoc(operation.doc._id) + const doc = latestDoc || operation.doc + await deleteFn(doc, operation.id) + } + + // Redo CHANGE + else { + // Get the current doc and apply the forwards patch on top of it + let doc = jsonpatch.deepClone(getDoc(operation.doc._id)) + if (doc) { + jsonpatch.applyPatch(doc, jsonpatch.deepClone(operation.forwardPatch)) + await saveFn(doc, operation.id) + selectDoc?.(doc._id) + } + } + stopLoading() + } catch (error) { + stopLoading() + throw error + } + + // After hook + await afterAction?.(operation) + } + + return { + subscribe: derivedStore.subscribe, + wrapSaveDoc, + wrapDeleteDoc, + reset, + undo, + redo, + } +} diff --git a/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte b/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte index e852ee1a0d..b80ba45086 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/AutomationBuilder.svelte @@ -1,10 +1,10 @@ -{#if automation} - +{#if $selectedAutomation} + {#key $selectedAutomation._id} + + {/key} {/if} diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte index caf8835b86..f30b49eb39 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ActionModal.svelte @@ -5,7 +5,6 @@ Detail, Body, Icon, - Tooltip, notifications, } from "@budibase/bbui" import { automationStore } from "builderStore" @@ -13,7 +12,6 @@ import { externalActions } from "./ExternalActions" export let blockIdx - export let blockComplete const disabled = { SEND_EMAIL_SMTP: { @@ -50,15 +48,12 @@ async function addBlockToAutomation() { try { - const newBlock = $automationStore.selectedAutomation.constructBlock( + const newBlock = automationStore.actions.constructBlock( "ACTION", actionVal.stepId, actionVal ) - automationStore.actions.addBlockToAutomation(newBlock, blockIdx + 1) - await automationStore.actions.save( - $automationStore.selectedAutomation?.automation - ) + await automationStore.actions.addBlockToAutomation(newBlock, blockIdx + 1) } catch (error) { notifications.error("Error saving automation") } @@ -66,20 +61,14 @@ { - blockComplete = true - addBlockToAutomation() - }} + onConfirm={addBlockToAutomation} > - Select an app or event. - - - Apps - + + Apps
{#each Object.entries(external) as [idx, action]}
- {idx.charAt(0).toUpperCase() + idx.slice(1)} + + {idx.charAt(0).toUpperCase() + idx.slice(1)} + +
{/each} +
+ Actions -
{#each Object.entries(internal) as [idx, action]} - {#if disabled[idx] && disabled[idx].disabled} - -
selectAction(action)} - > -
- - - {action.name} -
-
-
- {:else} -
selectAction(action)} - > -
- - - {action.name} -
+ {@const isDisabled = disabled[idx] && disabled[idx].disabled} +
selectAction(action)} + > +
+ + {action.name} + {#if isDisabled} + + {/if}
- {/if} +
{/each}
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte index 4b01616b54..63a3478ef3 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowChart.svelte @@ -1,5 +1,5 @@
-
+
{automation.name} -
-
-
-
-
- -
+
+ + +
{ testDataModal.show() @@ -62,15 +60,13 @@ icon="MultipleCheck" size="M">Run test -
- { - $automationStore.showTestPanel = true - }} - size="M">Test Details -
+ { + $automationStore.showTestPanel = true + }} + size="M">Test Details
@@ -80,7 +76,7 @@
{#if block.stepId !== ActionStepID.LOOP} @@ -105,6 +101,9 @@ diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte index d6e5fcb36d..7484a60502 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte @@ -1,5 +1,5 @@
{}}> - {#if loopingSelected} + {#if loopBlock}
{ @@ -174,13 +142,8 @@
-
{ - onSelect(block) - }} - > - +
{}}> +
@@ -198,9 +161,7 @@ $automationStore.blockDefinitions.ACTION.LOOP.schema.inputs .properties )} - block={$automationStore.selectedAutomation?.automation.definition.steps.find( - x => x.blockToLoop === block.id - )} + block={loopBlock} {webhookModal} /> @@ -209,22 +170,28 @@ {/if} {/if} - - {#if !blockComplete} + (open = !open)} + /> + {#if open}
{#if !isTrigger}
- {#if !loopingSelected} - addLooping()} icon="Reuse" - >Add Looping + {#if !loopBlock} + addLooping()} icon="Reuse"> + Add Looping + {/if} {#if showBindingPicker}