Use new string-templates function and remove the one implemented on this branch for finding HBS expressions

This commit is contained in:
Andrew Kingston 2022-03-07 09:32:31 +00:00
commit 018b8713d7
44 changed files with 762 additions and 442 deletions

View File

@ -38,6 +38,17 @@ jobs:
fi fi
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
- name: Tag and release Proxy service docker image
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build:docker:proxy:prod
docker tag budibase/proxy:$release_tag budibase/proxy:$PROD_TAG
docker push budibase/proxy:$PROD_TAG
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
PROD_TAG: k8s
- name: Configure AWS Credentials - name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1 uses: aws-actions/configure-aws-credentials@v1
with: with:

View File

@ -23,12 +23,24 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-1 aws-region: eu-west-1
- name: Get the latest budibase release version - name: Get the latest budibase release version
id: version id: version
run: | run: |
release_version=$(cat lerna.json | jq -r '.version') release_version=$(cat lerna.json | jq -r '.version')
echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
- name: Tag and release Proxy service docker image
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
yarn build:docker:proxy:preprod
docker tag budibase/proxy:$release_tag budibase/proxy:$PREPROD_TAG
docker push budibase/proxy:$PREPROD_TAG
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }}
PREPROD_TAG: k8s-preprod
- name: Pull values.yaml from budibase-infra - name: Pull values.yaml from budibase-infra
run: | run: |
curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \ curl -H "Authorization: token ${{ secrets.GH_PERSONAL_TOKEN }}" \

View File

@ -19,13 +19,7 @@ http {
tcp_nodelay on; tcp_nodelay on;
server_tokens off; server_tokens off;
types_hash_max_size 2048; types_hash_max_size 2048;
{{#if compose}} resolver {{ resolver }} valid=10s ipv6=off;
resolver 127.0.0.11 ipv6=off;
{{/if}}
{{#if k8s}}
resolver kube-dns.kube-system.svc.cluster.local valid=10s;
{{/if}}
# buffering # buffering
client_body_buffer_size 1K; client_body_buffer_size 1K;
@ -55,7 +49,7 @@ http {
add_header X-Frame-Options SAMEORIGIN always; add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always; add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always; add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com; frame-src 'self'; img-src http: https: data; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me https://maxcdn.bootstrapcdn.com; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me https://maxcdn.bootstrapcdn.com; frame-src 'self' https:; img-src http: https: data; manifest-src 'self'; media-src 'self'; worker-src 'none';" always;
# upstreams # upstreams
set $apps {{ apps }}; set $apps {{ apps }};

View File

@ -1,145 +0,0 @@
user nginx;
error_log /var/log/nginx/error.log debug;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 33282;
events {
worker_connections 1024;
}
http {
limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=20r/s;
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
types_hash_max_size 2048;
# buffering
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
ignore_invalid_headers off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
map $http_upgrade $connection_upgrade {
default "upgrade";
}
server {
listen 10000 default_server;
listen [::]:10000 default_server;
server_name _;
client_max_body_size 1000m;
ignore_invalid_headers off;
proxy_buffering off;
port_in_redirect off;
# Security Headers
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' data: https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src http: https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always;
location /app {
proxy_pass http://app-service:4002;
rewrite ^/app/(.*)$ /$1 break;
}
location = / {
port_in_redirect off;
proxy_pass http://app-service:4002;
}
location = /v1/update {
proxy_pass http://watchtower-service:8080;
}
location /builder/ {
port_in_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://app-service:4002;
}
location ~ ^/(builder|app_) {
port_in_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://app-service:4002;
}
location ~ ^/api/(system|admin|global)/ {
proxy_pass http://worker-service:4003;
}
location /worker/ {
proxy_pass http://worker-service:4003;
rewrite ^/worker/(.*)$ /$1 break;
}
location /api/ {
# calls to the API are rate limited with bursting
limit_req zone=ratelimit burst=20 nodelay;
# 120s timeout on API requests
proxy_read_timeout 120s;
proxy_connect_timeout 120s;
proxy_send_timeout 120s;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://app-service:4002;
}
location /db/ {
proxy_pass http://couchdb-service:5984;
rewrite ^/db/(.*)$ /$1 break;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_connect_timeout 300;
proxy_http_version 1.1;
proxy_set_header Connection "";
chunked_transfer_encoding off;
proxy_pass http://minio-service:9000;
}
client_header_timeout 60;
client_body_timeout 60;
keepalive_timeout 60;
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
}
}

View File

@ -1,5 +1,5 @@
{ {
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"npmClient": "yarn", "npmClient": "yarn",
"packages": [ "packages": [
"packages/*" "packages/*"

View File

@ -47,9 +47,9 @@
"build:specs": "lerna run specs", "build:specs": "lerna run specs",
"build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -", "build:docker": "lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh $BUDIBASE_RELEASE_VERSION && cd -",
"build:docker:proxy": "docker build hosting/proxy -t proxy-service", "build:docker:proxy": "docker build hosting/proxy -t proxy-service",
"build:docker:proxy:compose": "lerna run generate:proxy:compose && npm run build:docker:proxy", "build:docker:proxy:compose": "node scripts/proxy/generateProxyConfig compose && npm run build:docker:proxy",
"build:docker:proxy:preprod": "lerna run generate:proxy:preprod && npm run build:docker:proxy", "build:docker:proxy:preprod": "node scripts/proxy/generateProxyConfig preprod && npm run build:docker:proxy",
"build:docker:proxy:prod": "lerna run generate:proxy:prod && npm run build:docker:proxy", "build:docker:proxy:prod": "node scripts/proxy/generateProxyConfig prod && npm run build:docker:proxy",
"build:docker:selfhost": "lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh latest && cd -", "build:docker:selfhost": "lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh latest && cd -",
"build:docker:develop": "node scripts/pinVersions && lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh develop && cd -", "build:docker:develop": "node scripts/pinVersions && lerna run build:docker && npm run build:docker:proxy:compose && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh develop && cd -",
"build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild", "build:docker:airgap": "node hosting/scripts/airgapped/airgappedDockerBuild",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/backend-core", "name": "@budibase/backend-core",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Budibase backend core libraries used in server and worker", "description": "Budibase backend core libraries used in server and worker",
"main": "src/index.js", "main": "src/index.js",
"author": "Budibase", "author": "Budibase",

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/bbui", "name": "@budibase/bbui",
"description": "A UI solution used in the different Budibase projects.", "description": "A UI solution used in the different Budibase projects.",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"module": "dist/bbui.es.js", "module": "dist/bbui.es.js",
@ -38,7 +38,7 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "^1.2.1", "@adobe/spectrum-css-workflow-icons": "^1.2.1",
"@budibase/string-templates": "^1.0.79-alpha.7", "@budibase/string-templates": "^1.0.80-alpha.1",
"@spectrum-css/actionbutton": "^1.0.1", "@spectrum-css/actionbutton": "^1.0.1",
"@spectrum-css/actiongroup": "^1.0.1", "@spectrum-css/actiongroup": "^1.0.1",
"@spectrum-css/avatar": "^3.0.2", "@spectrum-css/avatar": "^3.0.2",

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/builder", "name": "@budibase/builder",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"license": "GPL-3.0", "license": "GPL-3.0",
"private": true, "private": true,
"scripts": { "scripts": {
@ -65,10 +65,10 @@
} }
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.0.79-alpha.7", "@budibase/bbui": "^1.0.80-alpha.1",
"@budibase/client": "^1.0.79-alpha.7", "@budibase/client": "^1.0.80-alpha.1",
"@budibase/frontend-core": "^1.0.79-alpha.7", "@budibase/frontend-core": "^1.0.80-alpha.1",
"@budibase/string-templates": "^1.0.79-alpha.7", "@budibase/string-templates": "^1.0.80-alpha.1",
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1", "@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1", "@spectrum-css/vars": "^3.0.1",

View File

@ -3,7 +3,7 @@ import { Helpers } from "@budibase/bbui"
import { import {
decodeJSBinding, decodeJSBinding,
encodeJSBinding, encodeJSBinding,
findAllBindings, findHBSBlocks,
} from "@budibase/string-templates" } from "@budibase/string-templates"
/** /**
@ -191,7 +191,7 @@ export const makeComponentUnique = component => {
children = children.replace(new RegExp(oldId, "g"), newId) children = children.replace(new RegExp(oldId, "g"), newId)
// Replace all instances of this ID in child JS bindings // Replace all instances of this ID in child JS bindings
const bindings = findAllBindings(children) const bindings = findHBSBlocks(children)
bindings.forEach(binding => { bindings.forEach(binding => {
// JSON.stringify will have escaped double quotes, so we need // JSON.stringify will have escaped double quotes, so we need
// to account for that // to account for that

View File

@ -7,6 +7,7 @@
import RoleSelect from "./PropertyControls/RoleSelect.svelte" import RoleSelect from "./PropertyControls/RoleSelect.svelte"
import ResetFieldsButton from "./PropertyControls/ResetFieldsButton.svelte" import ResetFieldsButton from "./PropertyControls/ResetFieldsButton.svelte"
import { getComponentForSettingType } from "./PropertyControls/componentSettings" import { getComponentForSettingType } from "./PropertyControls/componentSettings"
import { Utils } from "@budibase/frontend-core"
export let componentDefinition export let componentDefinition
export let componentInstance export let componentInstance
@ -40,13 +41,13 @@
] ]
} }
const updateProp = async (key, value) => { const updateProp = Utils.sequential(async (key, value) => {
try { try {
await store.actions.components.updateProp(key, value) await store.actions.components.updateProp(key, value)
} catch (error) { } catch (error) {
notifications.error("Error updating component prop") notifications.error("Error updating component prop")
} }
} })
const canRenderControl = setting => { const canRenderControl = setting => {
const control = getComponentForSettingType(setting?.type) const control = getComponentForSettingType(setting?.type)

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/cli", "name": "@budibase/cli",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Budibase CLI, for developers, self hosting and migrations.", "description": "Budibase CLI, for developers, self hosting and migrations.",
"main": "src/index.js", "main": "src/index.js",
"bin": { "bin": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/client", "name": "@budibase/client",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"license": "MPL-2.0", "license": "MPL-2.0",
"module": "dist/budibase-client.js", "module": "dist/budibase-client.js",
"main": "dist/budibase-client.js", "main": "dist/budibase-client.js",
@ -19,9 +19,9 @@
"dev:builder": "rollup -cw" "dev:builder": "rollup -cw"
}, },
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.0.79-alpha.7", "@budibase/bbui": "^1.0.80-alpha.1",
"@budibase/frontend-core": "^1.0.79-alpha.7", "@budibase/frontend-core": "^1.0.80-alpha.1",
"@budibase/string-templates": "^1.0.79-alpha.7", "@budibase/string-templates": "^1.0.80-alpha.1",
"@spectrum-css/button": "^3.0.3", "@spectrum-css/button": "^3.0.3",
"@spectrum-css/card": "^3.0.3", "@spectrum-css/card": "^3.0.3",
"@spectrum-css/divider": "^1.0.3", "@spectrum-css/divider": "^1.0.3",

View File

@ -17,7 +17,7 @@ export const getOptions = (
dataProvider?.rows?.forEach(row => { dataProvider?.rows?.forEach(row => {
const value = row?.[valueColumn] const value = row?.[valueColumn]
if (value) { if (value != null) {
const label = row[labelColumn] || value const label = row[labelColumn] || value
optionsSet[value] = { value, label } optionsSet[value] = { value, label }
} }
@ -30,7 +30,7 @@ export const getOptions = (
let optionsSet = {} let optionsSet = {}
dataProvider?.rows?.forEach(row => { dataProvider?.rows?.forEach(row => {
const value = row?.[valueColumn] const value = row?.[valueColumn]
if (value) { if (value != null) {
const label = row[labelColumn] || value const label = row[labelColumn] || value
optionsSet[value] = { value, label } optionsSet[value] = { value, label }
} }

View File

@ -1,12 +1,12 @@
{ {
"name": "@budibase/frontend-core", "name": "@budibase/frontend-core",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Budibase frontend core libraries used in builder and client", "description": "Budibase frontend core libraries used in builder and client",
"author": "Budibase", "author": "Budibase",
"license": "MPL-2.0", "license": "MPL-2.0",
"svelte": "src/index.js", "svelte": "src/index.js",
"dependencies": { "dependencies": {
"@budibase/bbui": "^1.0.79-alpha.7", "@budibase/bbui": "^1.0.80-alpha.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"svelte": "^3.46.2" "svelte": "^3.46.2"
} }

View File

@ -30,9 +30,11 @@ export const buildOtherEndpoints = API => ({
* Gets the version of the installed Budibase environment. * Gets the version of the installed Budibase environment.
*/ */
getBudibaseVersion: async () => { getBudibaseVersion: async () => {
return await API.get({ return (
await API.get({
url: "/api/dev/version", url: "/api/dev/version",
}).version })
).version
}, },
/** /**

View File

@ -1,7 +1,5 @@
export { createAPIClient } from "./api" export { createAPIClient } from "./api"
export { createLocalStorageStore } from "./stores/localStorage"
export { fetchData } from "./fetch/fetchData" export { fetchData } from "./fetch/fetchData"
export * as Constants from "./constants" export * as Constants from "./constants"
export * as LuceneUtils from "./utils/lucene" export * from "./stores"
export * as JSONUtils from "./utils/json" export * from "./utils"
export * as CookieUtils from "./utils/cookies"

View File

@ -0,0 +1 @@
export { createLocalStorageStore } from "./localStorage"

View File

@ -0,0 +1,4 @@
export * as LuceneUtils from "./lucene"
export * as JSONUtils from "./json"
export * as CookieUtils from "./cookies"
export * as Utils from "./utils"

View File

@ -0,0 +1,17 @@
/**
* Utility to wrap an async function and ensure all invocations happen
* sequentially.
* @param fn the async function to run
* @return {Promise} a sequential version of the function
*/
export const sequential = fn => {
let promise
return async (...params) => {
if (promise) {
await promise
}
promise = fn(...params)
await promise
promise = null
}
}

View File

@ -0,0 +1,17 @@
module MySQLMock {
const mysql: any = {}
const client = {
connect: jest.fn(),
end: jest.fn(),
query: jest.fn(async () => {
return [[]]
}),
}
mysql.createConnection = jest.fn(async () => {
return client
})
module.exports = mysql
}

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/server", "name": "@budibase/server",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Budibase Web Server", "description": "Budibase Web Server",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -21,9 +21,6 @@
"dev:stack:down": "node scripts/dev/manage.js down", "dev:stack:down": "node scripts/dev/manage.js down",
"dev:stack:nuke": "node scripts/dev/manage.js nuke", "dev:stack:nuke": "node scripts/dev/manage.js nuke",
"dev:builder": "yarn run dev:stack:up && nodemon", "dev:builder": "yarn run dev:stack:up && nodemon",
"generate:proxy:compose": "node scripts/proxy/generateProxyConfig compose",
"generate:proxy:preprod": "node scripts/proxy/generateProxyConfig preprod",
"generate:proxy:prod": "node scripts/proxy/generateProxyConfig prod",
"format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write", "format": "prettier --config ../../.prettierrc.json 'src/**/*.ts' --write",
"specs": "node specs/generate.js && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts", "specs": "node specs/generate.js && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts",
"lint": "eslint --fix src/", "lint": "eslint --fix src/",
@ -74,9 +71,9 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@apidevtools/swagger-parser": "^10.0.3", "@apidevtools/swagger-parser": "^10.0.3",
"@budibase/backend-core": "^1.0.79-alpha.7", "@budibase/backend-core": "^1.0.80-alpha.1",
"@budibase/client": "^1.0.79-alpha.7", "@budibase/client": "^1.0.80-alpha.1",
"@budibase/string-templates": "^1.0.79-alpha.7", "@budibase/string-templates": "^1.0.80-alpha.1",
"@bull-board/api": "^3.7.0", "@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0", "@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",
@ -111,6 +108,7 @@
"koa-send": "5.0.0", "koa-send": "5.0.0",
"koa-session": "5.12.0", "koa-session": "5.12.0",
"koa-static": "5.0.0", "koa-static": "5.0.0",
"koa2-ratelimit": "^1.1.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"memorystream": "^0.3.1", "memorystream": "^0.3.1",
"mongodb": "3.6.3", "mongodb": "3.6.3",
@ -126,6 +124,7 @@
"pouchdb-all-dbs": "1.0.2", "pouchdb-all-dbs": "1.0.2",
"pouchdb-find": "^7.2.2", "pouchdb-find": "^7.2.2",
"pouchdb-replication-stream": "1.2.9", "pouchdb-replication-stream": "1.2.9",
"redis": "4",
"server-destroy": "1.0.1", "server-destroy": "1.0.1",
"svelte": "^3.38.2", "svelte": "^3.38.2",
"swagger-parser": "^10.0.3", "swagger-parser": "^10.0.3",
@ -151,6 +150,7 @@
"@types/koa-router": "^7.4.2", "@types/koa-router": "^7.4.2",
"@types/node": "^15.12.4", "@types/node": "^15.12.4",
"@types/oracledb": "^5.2.1", "@types/oracledb": "^5.2.1",
"@types/redis": "^4.0.11",
"@typescript-eslint/parser": "4.28.0", "@typescript-eslint/parser": "4.28.0",
"apidoc": "^0.50.2", "apidoc": "^0.50.2",
"babel-jest": "^27.0.2", "babel-jest": "^27.0.2",

View File

@ -8,9 +8,9 @@
To install oracle express edition simply run `docker-compose up` To install oracle express edition simply run `docker-compose up`
- A single instance pluggable database (PDB) will be created named `xepdb` - A single instance pluggable database (PDB) will be created named `xepdb1`
- The default password is configured in the compose file as `oracle` - The default password is configured in the compose file as `oracle`
- The `system`, `sys` and `pdbadmin` users all share this password - The `system` and `pdbadmin` users share this password
## Instant Client ## Instant Client

View File

@ -58,7 +58,7 @@ module External {
) { ) {
const primary = table.primary const primary = table.primary
// if passed in array need to copy for shifting etc // if passed in array need to copy for shifting etc
let idCopy = cloneDeep(id) let idCopy: undefined | string | any[] = cloneDeep(id)
if (filters) { if (filters) {
// need to map over the filters and make sure the _id field isn't present // need to map over the filters and make sure the _id field isn't present
for (let filter of Object.values(filters)) { for (let filter of Object.values(filters)) {

View File

@ -8,18 +8,54 @@ import authorized from "../../../middleware/authorized"
import { paramResource, paramSubResource } from "../../../middleware/resourceId" import { paramResource, paramSubResource } from "../../../middleware/resourceId"
import { CtxFn } from "./utils/Endpoint" import { CtxFn } from "./utils/Endpoint"
import mapperMiddleware from "./middleware/mapper" import mapperMiddleware from "./middleware/mapper"
import env from "../../../environment"
// below imports don't have declaration files
const Router = require("@koa/router") const Router = require("@koa/router")
const { RateLimit, Stores } = require("koa2-ratelimit")
const { const {
PermissionLevels, PermissionLevels,
PermissionTypes, PermissionTypes,
} = require("@budibase/backend-core/permissions") } = require("@budibase/backend-core/permissions")
const { getRedisOptions } = require("@budibase/backend-core/redis").utils
const PREFIX = "/api/public/v1" const PREFIX = "/api/public/v1"
// allow a lot more requests when in test
const DEFAULT_API_REQ_LIMIT_PER_SEC = env.isTest() ? 100 : 10
function getApiLimitPerSecond(): number {
if (!env.API_REQ_LIMIT_PER_SEC) {
return DEFAULT_API_REQ_LIMIT_PER_SEC
}
return parseInt(env.API_REQ_LIMIT_PER_SEC)
}
if (!env.isTest()) {
const REDIS_OPTS = getRedisOptions()
RateLimit.defaultOptions({
store: new Stores.Redis({
// @ts-ignore
socket: {
host: REDIS_OPTS.host,
port: REDIS_OPTS.port,
},
password: REDIS_OPTS.opts.password,
database: 1,
}),
})
}
// rate limiting, allows for 2 requests per second
const limiter = RateLimit.middleware({
interval: { sec: 1 },
// per ip, per interval
max: getApiLimitPerSecond(),
})
const publicRouter = new Router({ const publicRouter = new Router({
prefix: PREFIX, prefix: PREFIX,
}) })
publicRouter.use(limiter)
function addMiddleware( function addMiddleware(
endpoints: any, endpoints: any,
middleware: CtxFn, middleware: CtxFn,

View File

@ -45,6 +45,7 @@ module.exports = {
INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
MULTI_TENANCY: process.env.MULTI_TENANCY, MULTI_TENANCY: process.env.MULTI_TENANCY,
HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS, HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
API_REQ_LIMIT_PER_SEC: process.env.API_REQ_LIMIT_PER_SEC,
// environment // environment
NODE_ENV: process.env.NODE_ENV, NODE_ENV: process.env.NODE_ENV,
JEST_WORKER_ID: process.env.JEST_WORKER_ID, JEST_WORKER_ID: process.env.JEST_WORKER_ID,

View File

@ -5,5 +5,8 @@ export interface DatasourcePlus extends IntegrationBase {
tables: Record<string, Table> tables: Record<string, Table>
schemaErrors: Record<string, string> schemaErrors: Record<string, string>
// if the datasource supports the use of bindings directly (to protect against SQL injection)
// this returns the format of the identifier
getBindingIdentifier(): string
buildSchema(datasourceId: string, entities: Record<string, Table>): any buildSchema(datasourceId: string, entities: Record<string, Table>): any
} }

View File

@ -6,11 +6,10 @@ import {
} from "../definitions/datasource" } from "../definitions/datasource"
import { OAuth2Client } from "google-auth-library" import { OAuth2Client } from "google-auth-library"
import { DatasourcePlus } from "./base/datasourcePlus" import { DatasourcePlus } from "./base/datasourcePlus"
import { Row, Table, TableSchema } from "../definitions/common" import { Table, TableSchema } from "../definitions/common"
import { buildExternalTableId } from "./utils" import { buildExternalTableId } from "./utils"
import { DataSourceOperation, FieldTypes } from "../constants" import { DataSourceOperation, FieldTypes } from "../constants"
import { GoogleSpreadsheet } from "google-spreadsheet" import { GoogleSpreadsheet } from "google-spreadsheet"
import { table } from "console"
module GoogleSheetsModule { module GoogleSheetsModule {
const { getGlobalDB } = require("@budibase/backend-core/tenancy") const { getGlobalDB } = require("@budibase/backend-core/tenancy")
@ -112,6 +111,10 @@ module GoogleSheetsModule {
this.client = new GoogleSpreadsheet(spreadsheetId) this.client = new GoogleSpreadsheet(spreadsheetId)
} }
getBindingIdentifier() {
return ""
}
/** /**
* Pull the spreadsheet ID out from a valid google sheets URL * Pull the spreadsheet ID out from a valid google sheets URL
* @param spreadsheetId - the URL or standard spreadsheetId of the google sheet * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet

View File

@ -79,12 +79,30 @@ module MSSQLModule {
}, },
} }
async function internalQuery( class SqlServerIntegration extends Sql implements DatasourcePlus {
client: any, private readonly config: MSSQLConfig
private index: number = 0
static pool: any
public tables: Record<string, Table> = {}
public schemaErrors: Record<string, string> = {}
MASTER_TABLES = [
"spt_fallback_db",
"spt_fallback_dev",
"spt_fallback_usg",
"spt_monitor",
"MSreplication_options",
]
TABLES_SQL =
"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'"
async internalQuery(
query: SqlQuery, query: SqlQuery,
operation: string | undefined = undefined operation: string | undefined = undefined
) { ) {
const client = this.client
const request = client.request() const request = client.request()
this.index = 0
try { try {
if (Array.isArray(query.bindings)) { if (Array.isArray(query.bindings)) {
let count = 0 let count = 0
@ -105,22 +123,6 @@ module MSSQLModule {
} }
} }
class SqlServerIntegration extends Sql implements DatasourcePlus {
private readonly config: MSSQLConfig
static pool: any
public tables: Record<string, Table> = {}
public schemaErrors: Record<string, string> = {}
MASTER_TABLES = [
"spt_fallback_db",
"spt_fallback_dev",
"spt_fallback_usg",
"spt_monitor",
"MSreplication_options",
]
TABLES_SQL =
"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'"
getDefinitionSQL(tableName: string) { getDefinitionSQL(tableName: string) {
return `select * return `select *
from INFORMATION_SCHEMA.COLUMNS from INFORMATION_SCHEMA.COLUMNS
@ -165,6 +167,10 @@ module MSSQLModule {
} }
} }
getBindingIdentifier(): string {
return `(@p${this.index++})`
}
async connect() { async connect() {
try { try {
this.client = await this.pool.connect() this.client = await this.pool.connect()
@ -175,7 +181,7 @@ module MSSQLModule {
} }
async runSQL(sql: string) { async runSQL(sql: string) {
return (await internalQuery(this.client, getSqlQuery(sql))).recordset return (await this.internalQuery(getSqlQuery(sql))).recordset
} }
/** /**
@ -238,33 +244,32 @@ module MSSQLModule {
async read(query: SqlQuery | string) { async read(query: SqlQuery | string) {
await this.connect() await this.connect()
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.recordset return response.recordset
} }
async create(query: SqlQuery | string) { async create(query: SqlQuery | string) {
await this.connect() await this.connect()
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.recordset || [{ created: true }] return response.recordset || [{ created: true }]
} }
async update(query: SqlQuery | string) { async update(query: SqlQuery | string) {
await this.connect() await this.connect()
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.recordset || [{ updated: true }] return response.recordset || [{ updated: true }]
} }
async delete(query: SqlQuery | string) { async delete(query: SqlQuery | string) {
await this.connect() await this.connect()
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.recordset || [{ deleted: true }] return response.recordset || [{ deleted: true }]
} }
async query(json: QueryJson) { async query(json: QueryJson) {
await this.connect() await this.connect()
const operation = this._operation(json) const operation = this._operation(json)
const queryFn = (query: any, op: string) => const queryFn = (query: any, op: string) => this.internalQuery(query, op)
internalQuery(this.client, query, op)
const processFn = (result: any) => const processFn = (result: any) =>
result.recordset ? result.recordset : [{ [operation]: true }] result.recordset ? result.recordset : [{ [operation]: true }]
return this.queryWithReturning(json, queryFn, processFn) return this.queryWithReturning(json, queryFn, processFn)

View File

@ -16,7 +16,7 @@ import {
import { DatasourcePlus } from "./base/datasourcePlus" import { DatasourcePlus } from "./base/datasourcePlus"
module MySQLModule { module MySQLModule {
const mysql = require("mysql2") const mysql = require("mysql2/promise")
const Sql = require("./base/sql") const Sql = require("./base/sql")
interface MySQLConfig { interface MySQLConfig {
@ -29,7 +29,7 @@ module MySQLModule {
} }
const SCHEMA: Integration = { const SCHEMA: Integration = {
docs: "https://github.com/mysqljs/mysql", docs: "https://github.com/sidorares/node-mysql2",
plus: true, plus: true,
friendlyName: "MySQL", friendlyName: "MySQL",
description: description:
@ -80,36 +80,9 @@ module MySQLModule {
}, },
} }
function internalQuery(
client: any,
query: SqlQuery,
connect: boolean = true
): Promise<any[] | any> {
// Node MySQL is callback based, so we must wrap our call in a promise
return new Promise((resolve, reject) => {
if (connect) {
client.connect()
}
return client.query(
query.sql,
query.bindings || {},
(error: any, results: object[]) => {
if (error) {
reject(error)
} else {
resolve(results)
}
if (connect) {
client.end()
}
}
)
})
}
class MySQLIntegration extends Sql implements DatasourcePlus { class MySQLIntegration extends Sql implements DatasourcePlus {
private config: MySQLConfig private config: MySQLConfig
private readonly client: any private client: any
public tables: Record<string, Table> = {} public tables: Record<string, Table> = {}
public schemaErrors: Record<string, string> = {} public schemaErrors: Record<string, string> = {}
@ -119,17 +92,50 @@ module MySQLModule {
if (config.ssl && Object.keys(config.ssl).length === 0) { if (config.ssl && Object.keys(config.ssl).length === 0) {
delete config.ssl delete config.ssl
} }
this.client = mysql.createConnection(config) this.config = config
}
getBindingIdentifier(): string {
return "?"
}
async connect() {
this.client = await mysql.createConnection(this.config)
}
async disconnect() {
await this.client.end()
}
async internalQuery(
query: SqlQuery,
connect: boolean = true
): Promise<any[] | any> {
try {
if (connect) {
await this.connect()
}
// Node MySQL is callback based, so we must wrap our call in a promise
const response = await this.client.query(
query.sql,
query.bindings || []
)
return response[0]
} finally {
if (connect) {
await this.disconnect()
}
}
} }
async buildSchema(datasourceId: string, entities: Record<string, Table>) { async buildSchema(datasourceId: string, entities: Record<string, Table>) {
const tables: { [key: string]: Table } = {} const tables: { [key: string]: Table } = {}
const database = this.config.database const database = this.config.database
this.client.connect() await this.connect()
try {
// get the tables first // get the tables first
const tablesResp = await internalQuery( const tablesResp = await this.internalQuery(
this.client,
{ sql: "SHOW TABLES;" }, { sql: "SHOW TABLES;" },
false false
) )
@ -141,14 +147,16 @@ module MySQLModule {
for (let tableName of tableNames) { for (let tableName of tableNames) {
const primaryKeys = [] const primaryKeys = []
const schema: TableSchema = {} const schema: TableSchema = {}
const descResp = await internalQuery( const descResp = await this.internalQuery(
this.client,
{ sql: `DESCRIBE \`${tableName}\`;` }, { sql: `DESCRIBE \`${tableName}\`;` },
false false
) )
for (let column of descResp) { for (let column of descResp) {
const columnName = column.Field const columnName = column.Field
if (column.Key === "PRI" && primaryKeys.indexOf(column.Key) === -1) { if (
column.Key === "PRI" &&
primaryKeys.indexOf(column.Key) === -1
) {
primaryKeys.push(columnName) primaryKeys.push(columnName)
} }
const constraints = { const constraints = {
@ -174,38 +182,41 @@ module MySQLModule {
} }
} }
} }
} finally {
this.client.end() await this.disconnect()
}
const final = finaliseExternalTables(tables, entities) const final = finaliseExternalTables(tables, entities)
this.tables = final.tables this.tables = final.tables
this.schemaErrors = final.errors this.schemaErrors = final.errors
} }
async create(query: SqlQuery | string) { async create(query: SqlQuery | string) {
const results = await internalQuery(this.client, getSqlQuery(query)) const results = await this.internalQuery(getSqlQuery(query))
return results.length ? results : [{ created: true }] return results.length ? results : [{ created: true }]
} }
async read(query: SqlQuery | string) { async read(query: SqlQuery | string) {
return internalQuery(this.client, getSqlQuery(query)) return this.internalQuery(getSqlQuery(query))
} }
async update(query: SqlQuery | string) { async update(query: SqlQuery | string) {
const results = await internalQuery(this.client, getSqlQuery(query)) const results = await this.internalQuery(getSqlQuery(query))
return results.length ? results : [{ updated: true }] return results.length ? results : [{ updated: true }]
} }
async delete(query: SqlQuery | string) { async delete(query: SqlQuery | string) {
const results = await internalQuery(this.client, getSqlQuery(query)) const results = await this.internalQuery(getSqlQuery(query))
return results.length ? results : [{ deleted: true }] return results.length ? results : [{ deleted: true }]
} }
async query(json: QueryJson) { async query(json: QueryJson) {
this.client.connect() await this.connect()
const queryFn = (query: any) => internalQuery(this.client, query, false) try {
const output = await this.queryWithReturning(json, queryFn) const queryFn = (query: any) => this.internalQuery(query, false)
this.client.end() return await this.queryWithReturning(json, queryFn)
return output } finally {
await this.disconnect()
}
} }
} }

View File

@ -1,24 +1,24 @@
import { import {
Integration,
DatasourceFieldTypes, DatasourceFieldTypes,
Integration,
Operation,
QueryJson,
QueryTypes, QueryTypes,
SqlQuery, SqlQuery,
QueryJson,
Operation,
} from "../definitions/datasource" } from "../definitions/datasource"
import { import {
finaliseExternalTables,
getSqlQuery,
buildExternalTableId, buildExternalTableId,
convertSqlType, convertSqlType,
finaliseExternalTables,
getSqlQuery,
SqlClients, SqlClients,
} from "./utils" } from "./utils"
import oracledb, { import oracledb, {
ExecuteOptions, BindParameters,
Result,
Connection, Connection,
ConnectionAttributes, ConnectionAttributes,
BindParameters, ExecuteOptions,
Result,
} from "oracledb" } from "oracledb"
import Sql from "./base/sql" import Sql from "./base/sql"
import { Table } from "../definitions/common" import { Table } from "../definitions/common"
@ -137,6 +137,7 @@ module OracleModule {
class OracleIntegration extends Sql implements DatasourcePlus { class OracleIntegration extends Sql implements DatasourcePlus {
private readonly config: OracleConfig private readonly config: OracleConfig
private index: number = 1
public tables: Record<string, Table> = {} public tables: Record<string, Table> = {}
public schemaErrors: Record<string, string> = {} public schemaErrors: Record<string, string> = {}
@ -174,6 +175,10 @@ module OracleModule {
this.config = config this.config = config
} }
getBindingIdentifier(): string {
return `:${this.index++}`
}
/** /**
* Map the flat tabular columns and constraints data into a nested object * Map the flat tabular columns and constraints data into a nested object
*/ */
@ -233,20 +238,14 @@ module OracleModule {
return oracleTables return oracleTables
} }
private isSupportedColumn(column: OracleColumn) { private static isSupportedColumn(column: OracleColumn) {
if (UNSUPPORTED_TYPES.includes(column.type)) { return !UNSUPPORTED_TYPES.includes(column.type)
return false
} }
return true private static isAutoColumn(column: OracleColumn) {
} return !!(
column.default && column.default.toLowerCase().includes("nextval")
private isAutoColumn(column: OracleColumn) { )
if (column.default && column.default.toLowerCase().includes("nextval")) {
return true
}
return false
} }
/** /**
@ -254,7 +253,7 @@ module OracleModule {
* This matches the default behaviour for generating DDL used in knex. * This matches the default behaviour for generating DDL used in knex.
*/ */
private isBooleanType(column: OracleColumn): boolean { private isBooleanType(column: OracleColumn): boolean {
if ( return (
column.type.toLowerCase() === "number" && column.type.toLowerCase() === "number" &&
Object.values(column.constraints).filter(c => { Object.values(column.constraints).filter(c => {
if ( if (
@ -273,11 +272,7 @@ module OracleModule {
} }
return false return false
}).length > 0 }).length > 0
) { )
return true
}
return false
} }
private internalConvertType(column: OracleColumn): string { private internalConvertType(column: OracleColumn): string {
@ -317,7 +312,9 @@ module OracleModule {
// iterate each column on the table // iterate each column on the table
Object.values(oracleTable.columns) Object.values(oracleTable.columns)
// remove columns that we can't read / save // remove columns that we can't read / save
.filter(oracleColumn => this.isSupportedColumn(oracleColumn)) .filter(oracleColumn =>
OracleIntegration.isSupportedColumn(oracleColumn)
)
// match the order of the columns in the db // match the order of the columns in the db
.sort((c1, c2) => c1.id - c2.id) .sort((c1, c2) => c1.id - c2.id)
.forEach(oracleColumn => { .forEach(oracleColumn => {
@ -325,7 +322,7 @@ module OracleModule {
let fieldSchema = table.schema[columnName] let fieldSchema = table.schema[columnName]
if (!fieldSchema) { if (!fieldSchema) {
fieldSchema = { fieldSchema = {
autocolumn: this.isAutoColumn(oracleColumn), autocolumn: OracleIntegration.isAutoColumn(oracleColumn),
name: columnName, name: columnName,
type: this.internalConvertType(oracleColumn), type: this.internalConvertType(oracleColumn),
} }
@ -351,18 +348,13 @@ module OracleModule {
private async internalQuery<T>(query: SqlQuery): Promise<Result<T>> { private async internalQuery<T>(query: SqlQuery): Promise<Result<T>> {
let connection let connection
try { try {
this.index = 1
connection = await this.getConnection() connection = await this.getConnection()
const options: ExecuteOptions = { autoCommit: true } const options: ExecuteOptions = { autoCommit: true }
const bindings: BindParameters = query.bindings || [] const bindings: BindParameters = query.bindings || []
const result: Result<T> = await connection.execute<T>( return await connection.execute<T>(query.sql, bindings, options)
query.sql,
bindings,
options
)
return result
} finally { } finally {
if (connection) { if (connection) {
try { try {

View File

@ -103,30 +103,11 @@ module PostgresModule {
}, },
} }
async function internalQuery(client: any, query: SqlQuery) {
// need to handle a specific issue with json data types in postgres,
// new lines inside the JSON data will break it
if (query && query.sql) {
const matches = query.sql.match(JSON_REGEX)
if (matches && matches.length > 0) {
for (let match of matches) {
const escaped = escapeDangerousCharacters(match)
query.sql = query.sql.replace(match, escaped)
}
}
}
try {
return await client.query(query.sql, query.bindings || [])
} catch (err) {
// @ts-ignore
throw new Error(err)
}
}
class PostgresIntegration extends Sql implements DatasourcePlus { class PostgresIntegration extends Sql implements DatasourcePlus {
static pool: any static pool: any
private readonly client: any private readonly client: any
private readonly config: PostgresConfig private readonly config: PostgresConfig
private index: number = 1
public tables: Record<string, Table> = {} public tables: Record<string, Table> = {}
public schemaErrors: Record<string, string> = {} public schemaErrors: Record<string, string> = {}
@ -163,6 +144,32 @@ module PostgresModule {
this.setSchema() this.setSchema()
} }
getBindingIdentifier(): string {
return `$${this.index++}`
}
async internalQuery(query: SqlQuery) {
const client = this.client
this.index = 1
// need to handle a specific issue with json data types in postgres,
// new lines inside the JSON data will break it
if (query && query.sql) {
const matches = query.sql.match(JSON_REGEX)
if (matches && matches.length > 0) {
for (let match of matches) {
const escaped = escapeDangerousCharacters(match)
query.sql = query.sql.replace(match, escaped)
}
}
}
try {
return await client.query(query.sql, query.bindings || [])
} catch (err) {
// @ts-ignore
throw new Error(err)
}
}
setSchema() { setSchema() {
if (!this.config.schema) { if (!this.config.schema) {
this.config.schema = "public" this.config.schema = "public"
@ -241,22 +248,22 @@ module PostgresModule {
} }
async create(query: SqlQuery | string) { async create(query: SqlQuery | string) {
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.rows.length ? response.rows : [{ created: true }] return response.rows.length ? response.rows : [{ created: true }]
} }
async read(query: SqlQuery | string) { async read(query: SqlQuery | string) {
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.rows return response.rows
} }
async update(query: SqlQuery | string) { async update(query: SqlQuery | string) {
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.rows.length ? response.rows : [{ updated: true }] return response.rows.length ? response.rows : [{ updated: true }]
} }
async delete(query: SqlQuery | string) { async delete(query: SqlQuery | string) {
const response = await internalQuery(this.client, getSqlQuery(query)) const response = await this.internalQuery(getSqlQuery(query))
return response.rows.length ? response.rows : [{ deleted: true }] return response.rows.length ? response.rows : [{ deleted: true }]
} }
@ -266,11 +273,11 @@ module PostgresModule {
if (Array.isArray(input)) { if (Array.isArray(input)) {
const responses = [] const responses = []
for (let query of input) { for (let query of input) {
responses.push(await internalQuery(this.client, query)) responses.push(await this.internalQuery(query))
} }
return responses return responses
} else { } else {
const response = await internalQuery(this.client, input) const response = await this.internalQuery(input)
return response.rows.length ? response.rows : [{ [operation]: true }] return response.rows.length ? response.rows : [{ [operation]: true }]
} }
} }

View File

@ -19,7 +19,7 @@ describe("MySQL Integration", () => {
await config.integration.create({ await config.integration.create({
sql sql
}) })
expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) expect(config.integration.client.query).toHaveBeenCalledWith(sql, [])
}) })
it("calls the read method with the correct params", async () => { it("calls the read method with the correct params", async () => {
@ -27,7 +27,7 @@ describe("MySQL Integration", () => {
await config.integration.read({ await config.integration.read({
sql sql
}) })
expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) expect(config.integration.client.query).toHaveBeenCalledWith(sql, [])
}) })
it("calls the update method with the correct params", async () => { it("calls the update method with the correct params", async () => {
@ -35,7 +35,7 @@ describe("MySQL Integration", () => {
await config.integration.update({ await config.integration.update({
sql sql
}) })
expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) expect(config.integration.client.query).toHaveBeenCalledWith(sql, [])
}) })
it("calls the delete method with the correct params", async () => { it("calls the delete method with the correct params", async () => {
@ -43,7 +43,7 @@ describe("MySQL Integration", () => {
await config.integration.delete({ await config.integration.delete({
sql sql
}) })
expect(config.integration.client.query).toHaveBeenCalledWith(sql, {}, expect.any(Function)) expect(config.integration.client.query).toHaveBeenCalledWith(sql, [])
}) })
describe("no rows returned", () => { describe("no rows returned", () => {

View File

@ -40,7 +40,7 @@ const SQL_TYPE_MAP = {
export enum SqlClients { export enum SqlClients {
MS_SQL = "mssql", MS_SQL = "mssql",
POSTGRES = "pg", POSTGRES = "pg",
MY_SQL = "mysql", MY_SQL = "mysql2",
ORACLE = "oracledb", ORACLE = "oracledb",
} }

View File

@ -2,8 +2,12 @@ const threadUtils = require("./utils")
threadUtils.threadSetup() threadUtils.threadSetup()
const ScriptRunner = require("../utilities/scriptRunner") const ScriptRunner = require("../utilities/scriptRunner")
const { integrations } = require("../integrations") const { integrations } = require("../integrations")
const { processStringSync } = require("@budibase/string-templates") const {
processStringSync,
findHBSBlocks,
} = require("@budibase/string-templates")
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
const { isSQL } = require("../integrations/utils")
class QueryRunner { class QueryRunner {
constructor(input, flags = { noRecursiveQuery: false }) { constructor(input, flags = { noRecursiveQuery: false }) {
@ -23,23 +27,47 @@ class QueryRunner {
this.hasRerun = false this.hasRerun = false
} }
async execute() { interpolateSQL(fields, parameters, integration) {
let { datasource, fields, queryVerb, transformer } = this let sql = fields.sql
// pre-query, make sure datasource variables are added to parameters if (!sql) {
const parameters = await this.addDatasourceVariables() return fields
let query = this.enrichQueryFields(fields, parameters) }
const bindings = findHBSBlocks(sql)
// Add pagination values for REST queries let variables = []
if (this.pagination) { for (let binding of bindings) {
query.paginationValues = this.pagination let variable = integration.getBindingIdentifier()
variables.push(binding)
sql = sql.replace(binding, variable)
}
// replicate the knex structure
fields.sql = sql
fields.bindings = this.enrichQueryFields(variables, parameters)
return fields
} }
async execute() {
let { datasource, fields, queryVerb, transformer } = this
const Integration = integrations[datasource.source] const Integration = integrations[datasource.source]
if (!Integration) { if (!Integration) {
throw "Integration type does not exist." throw "Integration type does not exist."
} }
const integration = new Integration(datasource.config) const integration = new Integration(datasource.config)
// pre-query, make sure datasource variables are added to parameters
const parameters = await this.addDatasourceVariables()
let query
// handle SQL injections by interpolating the variables
if (isSQL(datasource)) {
query = this.interpolateSQL(fields, parameters, integration)
} else {
query = this.enrichQueryFields(fields, parameters)
}
// Add pagination values for REST queries
if (this.pagination) {
query.paginationValues = this.pagination
}
let output = threadUtils.formatResponse(await integration[queryVerb](query)) let output = threadUtils.formatResponse(await integration[queryVerb](query))
let rows = output, let rows = output,
info = undefined, info = undefined,
@ -179,7 +207,7 @@ class QueryRunner {
} }
enrichQueryFields(fields, parameters = {}) { enrichQueryFields(fields, parameters = {}) {
const enrichedQuery = {} const enrichedQuery = Array.isArray(fields) ? [] : {}
// enrich the fields with dynamic parameters // enrich the fields with dynamic parameters
for (let key of Object.keys(fields)) { for (let key of Object.keys(fields)) {

View File

@ -995,10 +995,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@budibase/backend-core@^1.0.79-alpha.5": "@budibase/backend-core@^1.0.79-alpha.9":
version "1.0.79-alpha.5" version "1.0.79-alpha.9"
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.79-alpha.5.tgz#dac73ccfcd2e6e63415cde6d76e4bf09043dc6b6" resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.79-alpha.9.tgz#5d770d65f0375d93a382d8a32d0427e935fb2152"
integrity sha512-m7/z55fp+EYVYEAyuQ2K//AcrfgzLBcR4EVjP+rrmbIhGFbLV2ASl5IBg9bcAYp0z2m816skJrY2asx9raWhgw== integrity sha512-EV9hreLMvapZqZ/P99u4Ke2hO1w1GamGBHFri5MzLA9Njc5YRJzoDoy/Awg7k1piu3OIW2Sjk0b5VA+v3iaMnA==
dependencies: dependencies:
"@techpass/passport-openidconnect" "^0.3.0" "@techpass/passport-openidconnect" "^0.3.0"
aws-sdk "^2.901.0" aws-sdk "^2.901.0"
@ -1068,7 +1068,7 @@
svelte-flatpickr "^3.2.3" svelte-flatpickr "^3.2.3"
svelte-portal "^1.0.0" svelte-portal "^1.0.0"
"@budibase/bbui@^1.0.79-alpha.5": "@budibase/bbui@^1.0.79-alpha.9":
version "1.58.13" version "1.58.13"
resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.58.13.tgz#59df9c73def2d81c75dcbd2266c52c19db88dbd7" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.58.13.tgz#59df9c73def2d81c75dcbd2266c52c19db88dbd7"
integrity sha512-Zk6CKXdBfKsTVzA1Xs5++shdSSZLfphVpZuKVbjfzkgtuhyH7ruucexuSHEpFsxjW5rEKgKIBoRFzCK5vPvN0w== integrity sha512-Zk6CKXdBfKsTVzA1Xs5++shdSSZLfphVpZuKVbjfzkgtuhyH7ruucexuSHEpFsxjW5rEKgKIBoRFzCK5vPvN0w==
@ -1080,14 +1080,14 @@
svelte-portal "^1.0.0" svelte-portal "^1.0.0"
turndown "^7.0.0" turndown "^7.0.0"
"@budibase/client@^1.0.79-alpha.5": "@budibase/client@^1.0.79-alpha.9":
version "1.0.79-alpha.5" version "1.0.79-alpha.9"
resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.79-alpha.5.tgz#d729858b10e6cd2a506fb63364a0e7ab3149780e" resolved "https://registry.yarnpkg.com/@budibase/client/-/client-1.0.79-alpha.9.tgz#526efb411c85cc871b0aa2717a6d1dce1c6496ef"
integrity sha512-OrBErU97YL67GggsLmcD46AUElSgtyFjZdCXi++3s4zaZYZxT4Ix2iFMrnslcpF87bv8xyiSt3vsyCPGKCU5wQ== integrity sha512-x9F7s02jcgU1QlpUaEDj1kvMJqRJPzw+wcZfFyVPkRjZtZo9PnzDXQ+kZ6bqiKfyf/qNJ1SM1jzEAl1uzUj7vA==
dependencies: dependencies:
"@budibase/bbui" "^1.0.79-alpha.5" "@budibase/bbui" "^1.0.79-alpha.9"
"@budibase/frontend-core" "^1.0.79-alpha.5" "@budibase/frontend-core" "^1.0.79-alpha.9"
"@budibase/string-templates" "^1.0.79-alpha.5" "@budibase/string-templates" "^1.0.79-alpha.9"
"@spectrum-css/button" "^3.0.3" "@spectrum-css/button" "^3.0.3"
"@spectrum-css/card" "^3.0.3" "@spectrum-css/card" "^3.0.3"
"@spectrum-css/divider" "^1.0.3" "@spectrum-css/divider" "^1.0.3"
@ -1106,12 +1106,12 @@
svelte-flatpickr "^3.1.0" svelte-flatpickr "^3.1.0"
svelte-spa-router "^3.0.5" svelte-spa-router "^3.0.5"
"@budibase/frontend-core@^1.0.79-alpha.5": "@budibase/frontend-core@^1.0.79-alpha.9":
version "1.0.79-alpha.5" version "1.0.79-alpha.9"
resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.79-alpha.5.tgz#7da5faf83d6cc5a59d8e038c2e9333e27bff35d5" resolved "https://registry.yarnpkg.com/@budibase/frontend-core/-/frontend-core-1.0.79-alpha.9.tgz#3441f03370744204d3614a106e8544ceb70b2abd"
integrity sha512-5xti0MdKRvNKwYUE5cp4rH8IwLPmuRz39ajck947ut2OWzXV9bt7SXzoKPSSzEGdCBA2DgzJpK3gQWYlqXiJiQ== integrity sha512-bZrV2ifcGGK/G1adAGqRHJ9OGGnGMzany9bonzInrF1YoqfT9TE9sGpfDdm7I8jfvSsidXUEY0/KJBLPMo4+4g==
dependencies: dependencies:
"@budibase/bbui" "^1.0.79-alpha.5" "@budibase/bbui" "^1.0.79-alpha.9"
lodash "^4.17.21" lodash "^4.17.21"
svelte "^3.46.2" svelte "^3.46.2"
@ -1158,10 +1158,10 @@
svelte-apexcharts "^1.0.2" svelte-apexcharts "^1.0.2"
svelte-flatpickr "^3.1.0" svelte-flatpickr "^3.1.0"
"@budibase/string-templates@^1.0.79-alpha.5": "@budibase/string-templates@^1.0.79-alpha.9":
version "1.0.79-alpha.5" version "1.0.79-alpha.9"
resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.79-alpha.5.tgz#063f5beca7d3b4a9757df77dcf1bd8a442d7522e" resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-1.0.79-alpha.9.tgz#5b1b9401f97ca691b4a74c10901bb878a14067b6"
integrity sha512-Rifn1h1Pn53KYCFX6GHmMq+fD4IEnfRXEWrf4RD7cy4TVCYqCIcI84tnzUwibkyuCbpDw4zh0RR0m4nemf7heg== integrity sha512-BlqiCLIobVDoXV4UBeyZ5UaTF8INihvmR+ihr0862TOhdcthSRkb2HOfoB3aAm5XYhe7NpLnJepDRG+1sefDgA==
dependencies: dependencies:
"@budibase/handlebars-helpers" "^0.11.8" "@budibase/handlebars-helpers" "^0.11.8"
dayjs "^1.10.4" dayjs "^1.10.4"
@ -1885,6 +1885,41 @@
path-to-regexp "^1.1.1" path-to-regexp "^1.1.1"
urijs "^1.19.0" urijs "^1.19.0"
"@node-redis/bloom@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@node-redis/bloom/-/bloom-1.0.1.tgz#144474a0b7dc4a4b91badea2cfa9538ce0a1854e"
integrity sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==
"@node-redis/client@1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.4.tgz#fe185750df3bcc07524f63fe8dbc8d14d22d6cbb"
integrity sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g==
dependencies:
cluster-key-slot "1.1.0"
generic-pool "3.8.2"
redis-parser "3.0.0"
yallist "4.0.0"
"@node-redis/graph@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@node-redis/graph/-/graph-1.0.0.tgz#baf8eaac4a400f86ea04d65ec3d65715fd7951ab"
integrity sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g==
"@node-redis/json@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8"
integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g==
"@node-redis/search@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.3.tgz#7c3d026bf994caf82019fd0c3924cfc09f041a29"
integrity sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw==
"@node-redis/time-series@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69"
integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA==
"@nodelib/fs.scandir@2.1.5": "@nodelib/fs.scandir@2.1.5":
version "2.1.5" version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@ -2351,6 +2386,11 @@
dependencies: dependencies:
"@babel/types" "^7.3.0" "@babel/types" "^7.3.0"
"@types/bluebird@*":
version "3.5.36"
resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652"
integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==
"@types/body-parser@*": "@types/body-parser@*":
version "1.19.2" version "1.19.2"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
@ -2383,6 +2423,13 @@
resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.4.tgz#de48cf01c79c9f1560bcfd8ae43217ab028657f8" resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.4.tgz#de48cf01c79c9f1560bcfd8ae43217ab028657f8"
integrity sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ== integrity sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==
"@types/continuation-local-storage@*":
version "3.2.4"
resolved "https://registry.yarnpkg.com/@types/continuation-local-storage/-/continuation-local-storage-3.2.4.tgz#655c8ffd9327aa60fb8ae773a5f2efbc973a7cbb"
integrity sha512-OT32vCVMymU1JMPKDeY0lX3cduAr0Pm/VwIbxygMeDS4lRcv57qYXn9bMwBRcRnEpXKBb/r4xYaZCARTZllP0A==
dependencies:
"@types/node" "*"
"@types/cookiejar@*": "@types/cookiejar@*":
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8"
@ -2538,6 +2585,16 @@
dependencies: dependencies:
"@types/koa" "*" "@types/koa" "*"
"@types/koa2-ratelimit@^0.9.2":
version "0.9.2"
resolved "https://registry.yarnpkg.com/@types/koa2-ratelimit/-/koa2-ratelimit-0.9.2.tgz#5853e2db9d61ea596ffa8c0ef5ec545c5f5351f0"
integrity sha512-wHBO8fCFUX86lc41GNj/WR1Ao6CW47bPWJO3b14LLSc8j927ev8F/ELj7FKXlyUPWC/CFKZTW8PpKLufjK8Eqg==
dependencies:
"@types/koa" "*"
"@types/mongoose" "5.10.5"
"@types/redis" "^2.8.0"
"@types/sequelize" "*"
"@types/koa@*", "@types/koa@^2.13.3": "@types/koa@*", "@types/koa@^2.13.3":
version "2.13.4" version "2.13.4"
resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b" resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.4.tgz#10620b3f24a8027ef5cbae88b393d1b31205726b"
@ -2552,11 +2609,38 @@
"@types/koa-compose" "*" "@types/koa-compose" "*"
"@types/node" "*" "@types/node" "*"
"@types/lodash@*":
version "4.14.179"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5"
integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==
"@types/mime@^1": "@types/mime@^1":
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
"@types/mongodb@*", "@types/mongodb@^4.0.7":
version "4.0.7"
resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-4.0.7.tgz#ebaa80c53b684ea52ccfe7721c0f5c9ef7b4f511"
integrity sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw==
dependencies:
mongodb "*"
"@types/mongoose@5.10.5":
version "5.10.5"
resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.10.5.tgz#0f4fb0440e8cf0213caec1e5c7b163dbd9847c56"
integrity sha512-37QMIA954T3n+HSksSNLlxZsqF8fMJu5S4dyPBod6gRxGtsXlQ9jUtL8BE8Seimv99u79eLXI3bggoCnSQ/fxQ==
dependencies:
"@types/mongodb" "*"
"@types/node" "*"
"@types/mongoose@^5.11.97":
version "5.11.97"
resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.11.97.tgz#80b0357f3de6807eb597262f52e49c3e13ee14d8"
integrity sha512-cqwOVYT3qXyLiGw7ueU2kX9noE8DPGRY6z8eUxudhXY8NZ7DMKYAxyZkLSevGfhCX3dO/AoX5/SO9lAzfjon0Q==
dependencies:
mongoose "*"
"@types/node@*", "@types/node@>=13.13.4": "@types/node@*", "@types/node@>=13.13.4":
version "16.11.7" version "16.11.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42"
@ -2608,6 +2692,20 @@
"@types/node" "*" "@types/node" "*"
safe-buffer "*" safe-buffer "*"
"@types/redis@^2.8.0":
version "2.8.32"
resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.32.tgz#1d3430219afbee10f8cfa389dad2571a05ecfb11"
integrity sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==
dependencies:
"@types/node" "*"
"@types/redis@^4.0.11":
version "4.0.11"
resolved "https://registry.yarnpkg.com/@types/redis/-/redis-4.0.11.tgz#0bb4c11ac9900a21ad40d2a6768ec6aaf651c0e1"
integrity sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==
dependencies:
redis "*"
"@types/request@^2.48.7": "@types/request@^2.48.7":
version "2.48.8" version "2.48.8"
resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c"
@ -2618,6 +2716,16 @@
"@types/tough-cookie" "*" "@types/tough-cookie" "*"
form-data "^2.5.0" form-data "^2.5.0"
"@types/sequelize@*":
version "4.28.11"
resolved "https://registry.yarnpkg.com/@types/sequelize/-/sequelize-4.28.11.tgz#8b0c530bac4e6d73a0416a94db0de820cc4d47c3"
integrity sha512-2zeMcB5ZI+u1UwxM4sa3gLu8eSp0Gk+emTKPWXuNk3ePFo4EUYLgmIhGV6b+kYoshXpZHG3nJVMK00tuh5vEQA==
dependencies:
"@types/bluebird" "*"
"@types/continuation-local-storage" "*"
"@types/lodash" "*"
"@types/validator" "*"
"@types/serve-static@*": "@types/serve-static@*":
version "1.13.10" version "1.13.10"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9"
@ -2649,6 +2757,24 @@
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40"
integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg==
"@types/validator@*":
version "13.7.1"
resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.1.tgz#cdab1b4779f6b1718a08de89d92d2603b71950cb"
integrity sha512-I6OUIZ5cYRk5lp14xSOAiXjWrfVoMZVjDuevBYgQDYzZIjsf2CAISpEcXOkFAtpAHbmWIDLcZObejqny/9xq5Q==
"@types/webidl-conversions@*":
version "6.1.1"
resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e"
integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==
"@types/whatwg-url@^8.2.1":
version "8.2.1"
resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4"
integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==
dependencies:
"@types/node" "*"
"@types/webidl-conversions" "*"
"@types/yargs-parser@*": "@types/yargs-parser@*":
version "20.2.1" version "20.2.1"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
@ -3774,6 +3900,13 @@ bson@^1.1.4:
resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a" resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a"
integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg== integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==
bson@^4.2.2, bson@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.1.tgz#2b5da517539bb0f7f3ffb54ac70a384ca899641c"
integrity sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw==
dependencies:
buffer "^5.6.0"
buffer-alloc-unsafe@^1.1.0: buffer-alloc-unsafe@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
@ -4124,7 +4257,7 @@ cls-hooked@^4.2.2:
emitter-listener "^1.0.1" emitter-listener "^1.0.1"
semver "^5.4.1" semver "^5.4.1"
cluster-key-slot@^1.1.0: cluster-key-slot@1.1.0, cluster-key-slot@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
@ -4564,6 +4697,13 @@ debug@4, debug@4.3.2, debug@^4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@
dependencies: dependencies:
ms "2.1.2" ms "2.1.2"
debug@4.x:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@^2.2.0, debug@^2.3.3: debug@^2.2.0, debug@^2.3.3:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -6103,6 +6243,11 @@ generate-function@^2.3.1:
dependencies: dependencies:
is-property "^1.0.2" is-property "^1.0.2"
generic-pool@3.8.2:
version "3.8.2"
resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9"
integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==
gensync@^1.0.0-beta.2: gensync@^1.0.0-beta.2:
version "1.0.0-beta.2" version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@ -6927,6 +7072,11 @@ ip-regex@^2.1.0:
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
is-accessor-descriptor@^0.1.6: is-accessor-descriptor@^0.1.6:
version "0.1.6" version "0.1.6"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@ -8501,6 +8651,11 @@ jws@^4.0.0:
jwa "^2.0.0" jwa "^2.0.0"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
kareem@2.3.4:
version "2.3.4"
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.4.tgz#b38c436fb4758775d919b2828b4009db59b52694"
integrity sha512-Vcrt8lcpVl0s8ePx634BxwRqmFo+5DcOhlmNadehxreMTIQi/9hOL/B3hZQQbK5DgMS7Lem3xABXV7/S3jy+7g==
keygrip@~1.0.3: keygrip@~1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc" resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc"
@ -8707,6 +8862,11 @@ koa-views@^7.0.1:
pretty "^2.0.0" pretty "^2.0.0"
resolve-path "^1.4.0" resolve-path "^1.4.0"
koa2-ratelimit@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.0.tgz#5ab432fdda7b2d63a4fb1b9a0d994c1264396aff"
integrity sha512-AumRCI8YO9TMF9trVP6j68K5qzi21ajZUOCb5VuPWq9pZw+FHXam275S5P1IDAlZjs1cDFBOAAkhwTdTbVCcsg==
koa@2.7.0: koa@2.7.0:
version "2.7.0" version "2.7.0"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.7.0.tgz#7e00843506942b9d82c6cc33749f657c6e5e7adf" resolved "https://registry.yarnpkg.com/koa/-/koa-2.7.0.tgz#7e00843506942b9d82c6cc33749f657c6e5e7adf"
@ -9485,6 +9645,26 @@ moment-timezone@^0.5.31:
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
mongodb-connection-string-url@^2.4.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz#f075c8d529e8d3916386018b8a396aed4f16e5ed"
integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA==
dependencies:
"@types/whatwg-url" "^8.2.1"
whatwg-url "^11.0.0"
mongodb@*:
version "4.4.0"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.4.0.tgz#3b14b9701067713d5c9afb6d6e4a86ca7b969824"
integrity sha512-1hPhutJj6yxxu0ymwsO0uEimTo+QTh3oQP6YHxmLneBFBOGydYFdnmDDuLiGWimAlMdRN9WuDXY+JGp47aeOwA==
dependencies:
bson "^4.6.1"
denque "^2.0.1"
mongodb-connection-string-url "^2.4.1"
socks "^2.6.1"
optionalDependencies:
saslprep "^1.0.3"
mongodb@3.6.3: mongodb@3.6.3:
version "3.6.3" version "3.6.3"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05"
@ -9498,6 +9678,43 @@ mongodb@3.6.3:
optionalDependencies: optionalDependencies:
saslprep "^1.0.0" saslprep "^1.0.0"
mongodb@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.3.1.tgz#e346f76e421ec6f47ddea5c8f5140e6181aaeb94"
integrity sha512-sNa8APSIk+r4x31ZwctKjuPSaeKuvUeNb/fu/3B6dRM02HpEgig7hTHM8A/PJQTlxuC/KFWlDlQjhsk/S43tBg==
dependencies:
bson "^4.6.1"
denque "^2.0.1"
mongodb-connection-string-url "^2.4.1"
socks "^2.6.1"
optionalDependencies:
saslprep "^1.0.3"
mongoose@*:
version "6.2.4"
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.2.4.tgz#c6ff4f84ab47b6c760e773424b0fd1f392d98563"
integrity sha512-3hA3IGxBzZdlp1+/I9qn53NjEAd01qvKAH2WUCPahjVO8+uAmR0B4m+1bC3x9a4r0ExY8QYQ2ryG3E/v5Tj+jA==
dependencies:
bson "^4.2.2"
kareem "2.3.4"
mongodb "4.3.1"
mpath "0.8.4"
mquery "4.0.2"
ms "2.1.3"
sift "16.0.0"
mpath@0.8.4:
version "0.8.4"
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313"
integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==
mquery@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.2.tgz#a13add5ecd7c2e5a67e0f814b3c7acdfb6772804"
integrity sha512-oAVF0Nil1mT3rxty6Zln4YiD6x6QsUWYz927jZzjMxOK2aqmhEz5JQ7xmrKK7xRFA2dwV+YaOpKU/S+vfNqKxA==
dependencies:
debug "4.x"
mri@1.1.4: mri@1.1.4:
version "1.1.4" version "1.1.4"
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
@ -9518,7 +9735,7 @@ ms@2.1.2, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.1.3: ms@2.1.3, ms@^2.1.3:
version "2.1.3" version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@ -11176,13 +11393,25 @@ redis-info@^3.0.8:
dependencies: dependencies:
lodash "^4.17.11" lodash "^4.17.11"
redis-parser@^3.0.0: redis-parser@3.0.0, redis-parser@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
dependencies: dependencies:
redis-errors "^1.0.0" redis-errors "^1.0.0"
redis@*, redis@4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.4.tgz#b567f82f59086df38433982f7f424b48e924ec7a"
integrity sha512-KaM1OAj/nGrSeybmmOWSMY0LXTGT6FVWgUZZrd2MYzXKJ+VGtqVaciGQeNMfZiQX+kDM8Ke4uttb54m2rm6V0A==
dependencies:
"@node-redis/bloom" "1.0.1"
"@node-redis/client" "1.0.4"
"@node-redis/graph" "1.0.0"
"@node-redis/json" "1.0.2"
"@node-redis/search" "1.0.3"
"@node-redis/time-series" "1.0.2"
regenerate-unicode-properties@^9.0.0: regenerate-unicode-properties@^9.0.0:
version "9.0.0" version "9.0.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
@ -11563,7 +11792,7 @@ sanitize-s3-objectkey@^0.0.1:
resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e"
integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ==
saslprep@^1.0.0: saslprep@^1.0.0, saslprep@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226"
integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
@ -11757,6 +11986,11 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2" get-intrinsic "^1.0.2"
object-inspect "^1.9.0" object-inspect "^1.9.0"
sift@16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.0.tgz#447991577db61f1a8fab727a8a98a6db57a23eb8"
integrity sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==
sigmund@^1.0.1: sigmund@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
@ -11819,6 +12053,11 @@ slice-ansi@^2.1.0:
astral-regex "^1.0.0" astral-regex "^1.0.0"
is-fullwidth-code-point "^2.0.0" is-fullwidth-code-point "^2.0.0"
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
snapdragon-node@^2.0.1: snapdragon-node@^2.0.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@ -11849,6 +12088,14 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0" source-map-resolve "^0.5.0"
use "^3.1.0" use "^3.1.0"
socks@^2.6.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a"
integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==
dependencies:
ip "^1.1.5"
smart-buffer "^4.2.0"
sonic-boom@^1.0.2: sonic-boom@^1.0.2:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.4.1.tgz#d35d6a74076624f12e6f917ade7b9d75e918f53e"
@ -12829,6 +13076,13 @@ tr46@^2.1.0:
dependencies: dependencies:
punycode "^2.1.1" punycode "^2.1.1"
tr46@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9"
integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==
dependencies:
punycode "^2.1.1"
tr46@~0.0.3: tr46@~0.0.3:
version "0.0.3" version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@ -13358,6 +13612,11 @@ webidl-conversions@^6.1.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
webidl-conversions@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a"
integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==
webpack-cli@^4.9.1: webpack-cli@^4.9.1:
version "4.9.1" version "4.9.1"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3"
@ -13439,6 +13698,14 @@ whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
whatwg-url@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018"
integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==
dependencies:
tr46 "^3.0.0"
webidl-conversions "^7.0.0"
whatwg-url@^5.0.0: whatwg-url@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
@ -13712,16 +13979,16 @@ y18n@^5.0.5:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
yallist@4.0.0, yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yallist@^2.1.2: yallist@^2.1.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@2.0.0-1: yaml@2.0.0-1:
version "2.0.0-1" version "2.0.0-1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18"

View File

@ -1,6 +1,6 @@
{ {
"name": "@budibase/string-templates", "name": "@budibase/string-templates",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Handlebars wrapper for Budibase templating.", "description": "Handlebars wrapper for Budibase templating.",
"main": "src/index.cjs", "main": "src/index.cjs",
"module": "dist/bundle.mjs", "module": "dist/bundle.mjs",

View File

@ -18,7 +18,7 @@ module.exports.processObject = templates.processObject
module.exports.doesContainStrings = templates.doesContainStrings module.exports.doesContainStrings = templates.doesContainStrings
module.exports.doesContainString = templates.doesContainString module.exports.doesContainString = templates.doesContainString
module.exports.disableEscaping = templates.disableEscaping module.exports.disableEscaping = templates.disableEscaping
module.exports.findAllBindings = templates.findAllBindings module.exports.findHBSBlocks = templates.findHBSBlocks
/** /**
* Use vm2 to run JS scripts in a node env * Use vm2 to run JS scripts in a node env

View File

@ -3,7 +3,11 @@ const { registerAll, registerMinimum } = require("./helpers/index")
const processors = require("./processors") const processors = require("./processors")
const { atob, btoa } = require("./utilities") const { atob, btoa } = require("./utilities")
const manifest = require("../manifest.json") const manifest = require("../manifest.json")
const { FIND_HBS_REGEX, findDoubleHbsInstances } = require("./utilities") const {
FIND_HBS_REGEX,
FIND_ANY_HBS_REGEX,
findDoubleHbsInstances,
} = require("./utilities")
const hbsInstance = handlebars.create() const hbsInstance = handlebars.create()
registerAll(hbsInstance) registerAll(hbsInstance)
@ -310,6 +314,21 @@ module.exports.doesContainStrings = (template, strings) => {
return false return false
} }
/**
* Given a string, this will return any {{ binding }} or {{{ binding }}} type
* statements.
* @param {string} string The string to search within.
* @return {string[]} The found HBS blocks.
*/
module.exports.findHBSBlocks = string => {
let regexp = new RegExp(FIND_ANY_HBS_REGEX)
let matches = string.match(regexp)
if (matches == null) {
return []
}
return matches
}
/** /**
* This function looks in the supplied template for handlebars instances, if they contain * This function looks in the supplied template for handlebars instances, if they contain
* JS the JS will be decoded and then the supplied string will be looked for. For example * JS the JS will be decoded and then the supplied string will be looked for. For example
@ -322,12 +341,3 @@ module.exports.doesContainStrings = (template, strings) => {
module.exports.doesContainString = (template, string) => { module.exports.doesContainString = (template, string) => {
return exports.doesContainStrings(template, [string]) return exports.doesContainStrings(template, [string])
} }
/**
* Finds all regular (double bracketed) expressions inside a string.
* @param string the string to search
* @return {[]} all matching bindings
*/
module.exports.findAllBindings = string => {
return findDoubleHbsInstances(string)
}

View File

@ -18,7 +18,7 @@ export const processObject = templates.processObject
export const doesContainStrings = templates.doesContainStrings export const doesContainStrings = templates.doesContainStrings
export const doesContainString = templates.doesContainString export const doesContainString = templates.doesContainString
export const disableEscaping = templates.disableEscaping export const disableEscaping = templates.disableEscaping
export const findAllBindings = templates.findAllBindings export const findHBSBlocks = templates.findHBSBlocks
/** /**
* Use polyfilled vm to run JS scripts in a browser Env * Use polyfilled vm to run JS scripts in a browser Env

View File

@ -1,6 +1,7 @@
const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g const ALPHA_NUMERIC_REGEX = /^[A-Za-z0-9]+$/g
module.exports.FIND_HBS_REGEX = /{{([^{].*?)}}/g module.exports.FIND_HBS_REGEX = /{{([^{].*?)}}/g
module.exports.FIND_ANY_HBS_REGEX = /{?{{([^{].*?)}}}?/g
module.exports.FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g module.exports.FIND_TRIPLE_HBS_REGEX = /{{{([^{].*?)}}}/g
// originally this could be done with a single regex using look behinds // originally this could be done with a single regex using look behinds

View File

@ -7,6 +7,7 @@ const {
encodeJSBinding, encodeJSBinding,
doesContainString, doesContainString,
disableEscaping, disableEscaping,
findHBSBlocks,
} = require("../src/index.cjs") } = require("../src/index.cjs")
describe("Test that the string processing works correctly", () => { describe("Test that the string processing works correctly", () => {
@ -200,3 +201,13 @@ describe("check that disabling escaping function works", () => {
}) })
}) })
describe("check find hbs blocks function", () => {
it("should find none", () => {
expect(findHBSBlocks("hello there")).toEqual([])
})
it("should find two", () => {
expect(findHBSBlocks("{{ hello }} there {{{ name }}}")).toEqual(["{{ hello }}", "{{{ name }}}"])
})
})

View File

@ -1,7 +1,7 @@
{ {
"name": "@budibase/worker", "name": "@budibase/worker",
"email": "hi@budibase.com", "email": "hi@budibase.com",
"version": "1.0.79-alpha.7", "version": "1.0.80-alpha.1",
"description": "Budibase background service", "description": "Budibase background service",
"main": "src/index.ts", "main": "src/index.ts",
"repository": { "repository": {
@ -34,8 +34,8 @@
"author": "Budibase", "author": "Budibase",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@budibase/backend-core": "^1.0.79-alpha.7", "@budibase/backend-core": "^1.0.80-alpha.1",
"@budibase/string-templates": "^1.0.79-alpha.7", "@budibase/string-templates": "^1.0.80-alpha.1",
"@koa/router": "^8.0.0", "@koa/router": "^8.0.0",
"@sentry/node": "^6.0.0", "@sentry/node": "^6.0.0",
"@techpass/passport-openidconnect": "^0.3.0", "@techpass/passport-openidconnect": "^0.3.0",

View File

@ -1,30 +1,63 @@
#!/usr/bin/env node #!/usr/bin/env node
const path = require("path") const path = require("path")
const fs = require("fs") const fs = require("fs")
const { processStringSync } = require("@budibase/string-templates")
function processStringSync(string, env) {
let output = ""
// process if statements
let removal = false
for (let line of string.split("\n")) {
if (new RegExp(`{{\/if}}`, "g").test(line)) {
removal = false
continue
}
if (!removal) {
const match = line.match(new RegExp(`{{#if (.*)}}`))
if (match) {
const key = match[1]
// check the if statement is true
if (!env[key]) {
removal = true
}
continue
}
output += line + "\n"
}
}
for (let key in env) {
// replace variables
const rgx = new RegExp(`{{\\s*${key}\\s*}}`, "g")
output = output.replace(rgx, env[key])
}
return output
}
const Configs = { const Configs = {
prod: { prod: {
k8s: true,
apps: "app-service.budibase.svc.cluster.local", apps: "app-service.budibase.svc.cluster.local",
worker: "worker-service.budibase.svc.cluster.local", worker: "worker-service.budibase.svc.cluster.local",
minio: "minio-service.budibase.svc.cluster.local", minio: "minio-service.budibase.svc.cluster.local",
couchdb: "budibase-prod-svc-couchdb", couchdb: "budibase-prod-svc-couchdb",
resolver: "kube-dns.kube-system.svc.cluster.local"
}, },
preprod: { preprod: {
k8s: true,
apps: "app-service.budibase.svc.cluster.local", apps: "app-service.budibase.svc.cluster.local",
worker: "worker-service.budibase.svc.cluster.local", worker: "worker-service.budibase.svc.cluster.local",
minio: "minio-service.budibase.svc.cluster.local", minio: "minio-service.budibase.svc.cluster.local",
couchdb: "budibase-preprod-svc-couchdb", couchdb: "budibase-preprod-svc-couchdb",
resolver: "kube-dns.kube-system.svc.cluster.local"
}, },
compose: { compose: {
compose: true,
apps: "app-service", apps: "app-service",
worker: "worker-service", worker: "worker-service",
minio: "minio-service", minio: "minio-service",
couchdb: "couchdb-service", couchdb: "couchdb-service",
watchtower: "watchtower-service", watchtower: "watchtower-service",
resolver: "127.0.0.11"
}, },
} }
@ -36,7 +69,7 @@ const Commands = {
async function init(managementCommand) { async function init(managementCommand) {
const config = Configs[managementCommand] const config = Configs[managementCommand]
const hostingPath = path.join(process.cwd(), "..", "..", "hosting") const hostingPath = path.join(process.cwd(), "hosting")
const nginxHbsPath = path.join(hostingPath, "nginx.prod.conf.hbs") const nginxHbsPath = path.join(hostingPath, "nginx.prod.conf.hbs")
const nginxOutputPath = path.join( const nginxOutputPath = path.join(
hostingPath, hostingPath,