Merge branch 'master' into develop
This commit is contained in:
commit
0f98f2fcaa
|
@ -9,7 +9,11 @@ if [[ "${TARGETBUILD}" = "aas" ]]; then
|
|||
chown -R couchdb:couchdb $DATA_DIR/couch/
|
||||
apt update
|
||||
apt-get install -y openssh-server
|
||||
sed -i "s/#Port 22/Port 2222/" /etc/ssh/sshd_config
|
||||
echo "root:Docker!" | chpasswd
|
||||
mkdir -p /tmp
|
||||
chmod +x /tmp/ssh_setup.sh \
|
||||
&& (sleep 1;/tmp/ssh_setup.sh 2>&1 > /dev/null)
|
||||
cp /etc/sshd_config /etc/ssh/sshd_config
|
||||
/etc/init.d/ssh restart
|
||||
sed -i "s#DATA_DIR#/home#g" /opt/clouseau/clouseau.ini
|
||||
sed -i "s#DATA_DIR#/home#g" /opt/couchdb/etc/local.ini
|
||||
|
|
|
@ -29,23 +29,8 @@ ENV TARGETBUILD $TARGETBUILD
|
|||
COPY --from=build /app /app
|
||||
COPY --from=build /worker /worker
|
||||
|
||||
ENV \
|
||||
APP_PORT=4001 \
|
||||
ARCHITECTURE=amd \
|
||||
BUDIBASE_ENVIRONMENT=PRODUCTION \
|
||||
CLUSTER_PORT=80 \
|
||||
# CUSTOM_DOMAIN=budi001.custom.com \
|
||||
DATA_DIR=/data \
|
||||
DEPLOYMENT_ENVIRONMENT=docker \
|
||||
MINIO_URL=http://localhost:9000 \
|
||||
POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU \
|
||||
REDIS_URL=localhost:6379 \
|
||||
SELF_HOSTED=1 \
|
||||
TARGETBUILD=$TARGETBUILD \
|
||||
WORKER_PORT=4002 \
|
||||
WORKER_URL=http://localhost:4002 \
|
||||
APPS_URL=http://localhost:4001
|
||||
|
||||
# ENV CUSTOM_DOMAIN=budi001.custom.com \
|
||||
# See runner.sh for Env Vars
|
||||
# These secret env variables are generated by the runner at startup
|
||||
# their values can be overriden by the user, they will be written
|
||||
# to the .env file in the /data directory for use later on
|
||||
|
@ -117,6 +102,8 @@ RUN chmod +x ./build-target-paths.sh
|
|||
|
||||
# Script below sets the path for storing data based on $DATA_DIR
|
||||
# For Azure App Service install SSH & point data locations to /home
|
||||
ADD hosting/single/ssh/sshd_config /etc/
|
||||
ADD hosting/single/ssh/ssh_setup.sh /tmp
|
||||
RUN /build-target-paths.sh
|
||||
|
||||
# cleanup cache
|
||||
|
@ -124,6 +111,8 @@ RUN yarn cache clean -f
|
|||
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
# Expose port 2222 for SSH on Azure App Service build
|
||||
EXPOSE 2222
|
||||
VOLUME /data
|
||||
|
||||
# setup letsencrypt certificate
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
#!/bin/bash
|
||||
declare -a ENV_VARS=("COUCHDB_USER" "COUCHDB_PASSWORD" "DATA_DIR" "MINIO_ACCESS_KEY" "MINIO_SECRET_KEY" "INTERNAL_API_KEY" "JWT_SECRET" "REDIS_PASSWORD")
|
||||
|
||||
declare -a DOCKER_VARS=("APP_PORT" "APPS_URL" "ARCHITECTURE" "BUDIBASE_ENVIRONMENT" "CLUSTER_PORT" "DEPLOYMENT_ENVIRONMENT" "MINIO_URL" "NODE_ENV" "POSTHOG_TOKEN" "REDIS_URL" "SELF_HOSTED" "WORKER_PORT" "WORKER_URL")
|
||||
# Check the env vars set in Dockerfile have come through, AAS seems to drop them
|
||||
[[ -z "${APP_PORT}" ]] && export APP_PORT=4001
|
||||
[[ -z "${ARCHITECTURE}" ]] && export ARCHITECTURE=amd
|
||||
[[ -z "${BUDIBASE_ENVIRONMENT}" ]] && export BUDIBASE_ENVIRONMENT=PRODUCTION
|
||||
[[ -z "${CLUSTER_PORT}" ]] && export CLUSTER_PORT=80
|
||||
[[ -z "${DEPLOYMENT_ENVIRONMENT}" ]] && export DEPLOYMENT_ENVIRONMENT=docker
|
||||
[[ -z "${MINIO_URL}" ]] && export MINIO_URL=http://localhost:9000
|
||||
[[ -z "${NODE_ENV}" ]] && export NODE_ENV=production
|
||||
[[ -z "${POSTHOG_TOKEN}" ]] && export POSTHOG_TOKEN=phc_bIjZL7oh2GEUd2vqvTBH8WvrX0fWTFQMs6H5KQxiUxU
|
||||
[[ -z "${REDIS_URL}" ]] && export REDIS_URL=localhost:6379
|
||||
[[ -z "${SELF_HOSTED}" ]] && export SELF_HOSTED=1
|
||||
[[ -z "${WORKER_PORT}" ]] && export WORKER_PORT=4002
|
||||
[[ -z "${WORKER_URL}" ]] && export WORKER_URL=http://localhost:4002
|
||||
[[ -z "${APPS_URL}" ]] && export APPS_URL=http://localhost:4001
|
||||
# export CUSTOM_DOMAIN=budi001.custom.com
|
||||
# Azure App Service customisations
|
||||
if [[ "${TARGETBUILD}" = "aas" ]]; then
|
||||
DATA_DIR=/home
|
||||
|
@ -10,9 +25,10 @@ else
|
|||
fi
|
||||
|
||||
if [ -f "${DATA_DIR}/.env" ]; then
|
||||
export $(cat ${DATA_DIR}/.env | xargs)
|
||||
# Read in the .env file and export the variables
|
||||
for LINE in $(cat ${DATA_DIR}/.env); do export $LINE; done
|
||||
fi
|
||||
# first randomise any unset environment variables
|
||||
# randomise any unset environment variables
|
||||
for ENV_VAR in "${ENV_VARS[@]}"
|
||||
do
|
||||
temp=$(eval "echo \$$ENV_VAR")
|
||||
|
@ -30,11 +46,18 @@ if [ ! -f "${DATA_DIR}/.env" ]; then
|
|||
temp=$(eval "echo \$$ENV_VAR")
|
||||
echo "$ENV_VAR=$temp" >> ${DATA_DIR}/.env
|
||||
done
|
||||
for ENV_VAR in "${DOCKER_VARS[@]}"
|
||||
do
|
||||
temp=$(eval "echo \$$ENV_VAR")
|
||||
echo "$ENV_VAR=$temp" >> ${DATA_DIR}/.env
|
||||
done
|
||||
echo "COUCH_DB_URL=${COUCH_DB_URL}" >> ${DATA_DIR}/.env
|
||||
fi
|
||||
|
||||
export COUCH_DB_URL=http://$COUCHDB_USER:$COUCHDB_PASSWORD@localhost:5984
|
||||
|
||||
# Read in the .env file and export the variables
|
||||
for LINE in $(cat ${DATA_DIR}/.env); do export $LINE; done
|
||||
ln -s ${DATA_DIR}/.env /app/.env
|
||||
ln -s ${DATA_DIR}/.env /worker/.env
|
||||
# make these directories in runner, incase of mount
|
||||
mkdir -p ${DATA_DIR}/couch/{dbs,views}
|
||||
mkdir -p ${DATA_DIR}/minio
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
|
||||
ssh-keygen -A
|
||||
|
||||
#prepare run dir
|
||||
if [ ! -d "/var/run/sshd" ]; then
|
||||
mkdir -p /var/run/sshd
|
||||
fi
|
|
@ -0,0 +1,12 @@
|
|||
Port 2222
|
||||
ListenAddress 0.0.0.0
|
||||
LoginGraceTime 180
|
||||
X11Forwarding yes
|
||||
Ciphers aes128-cbc,3des-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
|
||||
MACs hmac-sha1,hmac-sha1-96
|
||||
StrictModes yes
|
||||
SyslogFacility DAEMON
|
||||
PasswordAuthentication yes
|
||||
PermitEmptyPasswords no
|
||||
PermitRootLogin yes
|
||||
Subsystem sftp internal-sftp
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/backend-core",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "dist/src/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"test:watch": "jest --watchAll"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/types": "1.3.15-alpha.9",
|
||||
"@budibase/types": "^1.3.18",
|
||||
"@shopify/jest-koa-mocks": "5.0.1",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
"aws-sdk": "2.1030.0",
|
||||
|
|
|
@ -19,6 +19,7 @@ export enum ViewName {
|
|||
ROUTING = "screen_routes",
|
||||
AUTOMATION_LOGS = "automation_logs",
|
||||
ACCOUNT_BY_EMAIL = "account_by_email",
|
||||
PLATFORM_USERS_LOWERCASE = "platform_users_lowercase",
|
||||
}
|
||||
|
||||
export const DeprecatedViews = {
|
||||
|
|
|
@ -2,7 +2,8 @@ import { newid } from "../hashing"
|
|||
import { DEFAULT_TENANT_ID, Configs } from "../constants"
|
||||
import env from "../environment"
|
||||
import { SEPARATOR, DocumentType, UNICODE_MAX, ViewName } from "./constants"
|
||||
import { getTenantId, getGlobalDBName, getGlobalDB } from "../tenancy"
|
||||
import { getTenantId, getGlobalDB } from "../context"
|
||||
import { getGlobalDBName } from "../tenancy/utils"
|
||||
import fetch from "node-fetch"
|
||||
import { doWithDB, allDbs } from "./index"
|
||||
import { getCouchInfo } from "./pouch"
|
||||
|
|
|
@ -1,203 +0,0 @@
|
|||
const {
|
||||
DocumentType,
|
||||
ViewName,
|
||||
DeprecatedViews,
|
||||
SEPARATOR,
|
||||
} = require("./utils")
|
||||
const { getGlobalDB } = require("../tenancy")
|
||||
const { StaticDatabases } = require("./constants")
|
||||
const { doWithDB } = require("./")
|
||||
|
||||
const DESIGN_DB = "_design/database"
|
||||
|
||||
function DesignDoc() {
|
||||
return {
|
||||
_id: DESIGN_DB,
|
||||
// view collation information, read before writing any complex views:
|
||||
// https://docs.couchdb.org/en/master/ddocs/views/collation.html#collation-specification
|
||||
views: {},
|
||||
}
|
||||
}
|
||||
|
||||
async function removeDeprecated(db, viewName) {
|
||||
if (!DeprecatedViews[viewName]) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const designDoc = await db.get(DESIGN_DB)
|
||||
for (let deprecatedNames of DeprecatedViews[viewName]) {
|
||||
delete designDoc.views[deprecatedNames]
|
||||
}
|
||||
await db.put(designDoc)
|
||||
} catch (err) {
|
||||
// doesn't exist, ignore
|
||||
}
|
||||
}
|
||||
|
||||
exports.createNewUserEmailView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get(DESIGN_DB)
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}")) {
|
||||
emit(doc.email.toLowerCase(), doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_EMAIL]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createAccountEmailView = async () => {
|
||||
await doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => {
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get(DESIGN_DB)
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.ACCOUNT_METADATA}${SEPARATOR}")) {
|
||||
emit(doc.email.toLowerCase(), doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.ACCOUNT_BY_EMAIL]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
})
|
||||
}
|
||||
|
||||
exports.createUserAppView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}") && doc.roles) {
|
||||
for (let prodAppId of Object.keys(doc.roles)) {
|
||||
let emitted = prodAppId + "${SEPARATOR}" + doc._id
|
||||
emit(emitted, null)
|
||||
}
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_APP]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createApiKeyView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.DEV_INFO}") && doc.apiKey) {
|
||||
emit(doc.apiKey, doc.userId)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.BY_API_KEY]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createUserBuildersView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
map: `function(doc) {
|
||||
if (doc.builder && doc.builder.global === true) {
|
||||
emit(doc._id, doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_BUILDERS]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.queryView = async (viewName, params, db, CreateFuncByName) => {
|
||||
try {
|
||||
let response = (await db.query(`database/${viewName}`, params)).rows
|
||||
response = response.map(resp =>
|
||||
params.include_docs ? resp.doc : resp.value
|
||||
)
|
||||
if (params.arrayResponse) {
|
||||
return response
|
||||
} else {
|
||||
return response.length <= 1 ? response[0] : response
|
||||
}
|
||||
} catch (err) {
|
||||
if (err != null && err.name === "not_found") {
|
||||
const createFunc = CreateFuncByName[viewName]
|
||||
await removeDeprecated(db, viewName)
|
||||
await createFunc()
|
||||
return exports.queryView(viewName, params, db, CreateFuncByName)
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.queryPlatformView = async (viewName, params) => {
|
||||
const CreateFuncByName = {
|
||||
[ViewName.ACCOUNT_BY_EMAIL]: exports.createAccountEmailView,
|
||||
}
|
||||
|
||||
return doWithDB(StaticDatabases.PLATFORM_INFO.name, async db => {
|
||||
return exports.queryView(viewName, params, db, CreateFuncByName)
|
||||
})
|
||||
}
|
||||
|
||||
exports.queryGlobalView = async (viewName, params, db = null) => {
|
||||
const CreateFuncByName = {
|
||||
[ViewName.USER_BY_EMAIL]: exports.createNewUserEmailView,
|
||||
[ViewName.BY_API_KEY]: exports.createApiKeyView,
|
||||
[ViewName.USER_BY_BUILDERS]: exports.createUserBuildersView,
|
||||
[ViewName.USER_BY_APP]: exports.createUserAppView,
|
||||
}
|
||||
// can pass DB in if working with something specific
|
||||
if (!db) {
|
||||
db = getGlobalDB()
|
||||
}
|
||||
return exports.queryView(viewName, params, db, CreateFuncByName)
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
import { DocumentType, ViewName, DeprecatedViews, SEPARATOR } from "./utils"
|
||||
import { getGlobalDB } from "../context"
|
||||
import { StaticDatabases } from "./constants"
|
||||
import { doWithDB } from "./"
|
||||
|
||||
const DESIGN_DB = "_design/database"
|
||||
|
||||
function DesignDoc() {
|
||||
return {
|
||||
_id: DESIGN_DB,
|
||||
// view collation information, read before writing any complex views:
|
||||
// https://docs.couchdb.org/en/master/ddocs/views/collation.html#collation-specification
|
||||
views: {},
|
||||
}
|
||||
}
|
||||
|
||||
interface DesignDocument {
|
||||
views: any
|
||||
}
|
||||
|
||||
async function removeDeprecated(db: PouchDB.Database, viewName: ViewName) {
|
||||
// @ts-ignore
|
||||
if (!DeprecatedViews[viewName]) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const designDoc = await db.get<DesignDocument>(DESIGN_DB)
|
||||
// @ts-ignore
|
||||
for (let deprecatedNames of DeprecatedViews[viewName]) {
|
||||
delete designDoc.views[deprecatedNames]
|
||||
}
|
||||
await db.put(designDoc)
|
||||
} catch (err) {
|
||||
// doesn't exist, ignore
|
||||
}
|
||||
}
|
||||
|
||||
export const createNewUserEmailView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get(DESIGN_DB)
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}")) {
|
||||
emit(doc.email.toLowerCase(), doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_EMAIL]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
export const createAccountEmailView = async () => {
|
||||
await doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (db: PouchDB.Database) => {
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get<DesignDocument>(DESIGN_DB)
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.ACCOUNT_METADATA}${SEPARATOR}")) {
|
||||
emit(doc.email.toLowerCase(), doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.ACCOUNT_BY_EMAIL]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const createUserAppView = async () => {
|
||||
const db = getGlobalDB() as PouchDB.Database
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get<DesignDocument>("_design/database")
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}") && doc.roles) {
|
||||
for (let prodAppId of Object.keys(doc.roles)) {
|
||||
let emitted = prodAppId + "${SEPARATOR}" + doc._id
|
||||
emit(emitted, null)
|
||||
}
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_APP]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
export const createApiKeyView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
map: `function(doc) {
|
||||
if (doc._id.startsWith("${DocumentType.DEV_INFO}") && doc.apiKey) {
|
||||
emit(doc.apiKey, doc.userId)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.BY_API_KEY]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
export const createUserBuildersView = async () => {
|
||||
const db = getGlobalDB()
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
map: `function(doc) {
|
||||
if (doc.builder && doc.builder.global === true) {
|
||||
emit(doc._id, doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.USER_BY_BUILDERS]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
export const createPlatformUserView = async () => {
|
||||
await doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (db: PouchDB.Database) => {
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get<DesignDocument>(DESIGN_DB)
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
const view = {
|
||||
// if using variables in a map function need to inject them before use
|
||||
map: `function(doc) {
|
||||
if (doc.tenantId) {
|
||||
emit(doc._id.toLowerCase(), doc._id)
|
||||
}
|
||||
}`,
|
||||
}
|
||||
designDoc.views = {
|
||||
...designDoc.views,
|
||||
[ViewName.PLATFORM_USERS_LOWERCASE]: view,
|
||||
}
|
||||
await db.put(designDoc)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export interface QueryViewOptions {
|
||||
arrayResponse?: boolean
|
||||
}
|
||||
|
||||
export const queryView = async <T>(
|
||||
viewName: ViewName,
|
||||
params: PouchDB.Query.Options<T, T>,
|
||||
db: PouchDB.Database,
|
||||
CreateFuncByName: any,
|
||||
opts?: QueryViewOptions
|
||||
): Promise<T[] | T | undefined> => {
|
||||
try {
|
||||
let response = await db.query<T, T>(`database/${viewName}`, params)
|
||||
const rows = response.rows
|
||||
const docs = rows.map((resp: any) =>
|
||||
params.include_docs ? resp.doc : resp.value
|
||||
)
|
||||
|
||||
if (opts?.arrayResponse) {
|
||||
return docs
|
||||
} else {
|
||||
return docs.length <= 1 ? docs[0] : docs
|
||||
}
|
||||
} catch (err: any) {
|
||||
if (err != null && err.name === "not_found") {
|
||||
const createFunc = CreateFuncByName[viewName]
|
||||
await removeDeprecated(db, viewName)
|
||||
await createFunc()
|
||||
return queryView(viewName, params, db, CreateFuncByName, opts)
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const queryPlatformView = async <T>(
|
||||
viewName: ViewName,
|
||||
params: PouchDB.Query.Options<T, T>,
|
||||
opts?: QueryViewOptions
|
||||
): Promise<T[] | T | undefined> => {
|
||||
const CreateFuncByName = {
|
||||
[ViewName.ACCOUNT_BY_EMAIL]: createAccountEmailView,
|
||||
[ViewName.PLATFORM_USERS_LOWERCASE]: createPlatformUserView,
|
||||
}
|
||||
|
||||
return doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (db: PouchDB.Database) => {
|
||||
return queryView(viewName, params, db, CreateFuncByName, opts)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const queryGlobalView = async <T>(
|
||||
viewName: ViewName,
|
||||
params: PouchDB.Query.Options<T, T>,
|
||||
db?: PouchDB.Database,
|
||||
opts?: QueryViewOptions
|
||||
): Promise<T[] | T | undefined> => {
|
||||
const CreateFuncByName = {
|
||||
[ViewName.USER_BY_EMAIL]: createNewUserEmailView,
|
||||
[ViewName.BY_API_KEY]: createApiKeyView,
|
||||
[ViewName.USER_BY_BUILDERS]: createUserBuildersView,
|
||||
[ViewName.USER_BY_APP]: createUserAppView,
|
||||
}
|
||||
// can pass DB in if working with something specific
|
||||
if (!db) {
|
||||
db = getGlobalDB() as PouchDB.Database
|
||||
}
|
||||
return queryView(viewName, params, db, CreateFuncByName, opts)
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import * as context from "../context"
|
||||
import * as tenancy from "./tenancy"
|
||||
import * as utils from "./utils"
|
||||
|
||||
const pkg = {
|
||||
...context,
|
||||
...tenancy,
|
||||
...utils,
|
||||
}
|
||||
|
||||
export = pkg
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { doWithDB } from "../db"
|
||||
import { StaticDatabases } from "../db/constants"
|
||||
import { baseGlobalDBName } from "./utils"
|
||||
import { queryPlatformView } from "../db/views"
|
||||
import { StaticDatabases, ViewName } from "../db/constants"
|
||||
import { getGlobalDBName } from "./utils"
|
||||
import {
|
||||
getTenantId,
|
||||
DEFAULT_TENANT_ID,
|
||||
|
@ -8,6 +9,7 @@ import {
|
|||
getTenantIDFromAppID,
|
||||
} from "../context"
|
||||
import env from "../environment"
|
||||
import { PlatformUser, PlatformUserByEmail } from "@budibase/types"
|
||||
|
||||
const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name
|
||||
|
@ -87,15 +89,6 @@ export const tryAddTenant = async (
|
|||
})
|
||||
}
|
||||
|
||||
export const getGlobalDBName = (tenantId?: string) => {
|
||||
// tenant ID can be set externally, for example user API where
|
||||
// new tenants are being created, this may be the case
|
||||
if (!tenantId) {
|
||||
tenantId = getTenantId()
|
||||
}
|
||||
return baseGlobalDBName(tenantId)
|
||||
}
|
||||
|
||||
export const doWithGlobalDB = (tenantId: string, cb: any) => {
|
||||
return doWithDB(getGlobalDBName(tenantId), cb)
|
||||
}
|
||||
|
@ -116,14 +109,16 @@ export const lookupTenantId = async (userId: string) => {
|
|||
}
|
||||
|
||||
// lookup, could be email or userId, either will return a doc
|
||||
export const getTenantUser = async (identifier: string) => {
|
||||
return doWithDB(PLATFORM_INFO_DB, async (db: any) => {
|
||||
try {
|
||||
return await db.get(identifier)
|
||||
} catch (err) {
|
||||
return null
|
||||
}
|
||||
})
|
||||
export const getTenantUser = async (
|
||||
identifier: string
|
||||
): Promise<PlatformUser | null> => {
|
||||
// use the view here and allow to find anyone regardless of casing
|
||||
// Use lowercase to ensure email login is case insensitive
|
||||
const response = queryPlatformView(ViewName.PLATFORM_USERS_LOWERCASE, {
|
||||
keys: [identifier.toLowerCase()],
|
||||
include_docs: true,
|
||||
}) as Promise<PlatformUser>
|
||||
return response
|
||||
}
|
||||
|
||||
export const isUserInAppTenant = (appId: string, user: any) => {
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
const { DEFAULT_TENANT_ID } = require("../constants")
|
||||
const { StaticDatabases, SEPARATOR } = require("../db/constants")
|
||||
|
||||
exports.baseGlobalDBName = tenantId => {
|
||||
let dbName
|
||||
if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
|
||||
dbName = StaticDatabases.GLOBAL.name
|
||||
} else {
|
||||
dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`
|
||||
}
|
||||
return dbName
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { DEFAULT_TENANT_ID } from "../constants"
|
||||
import { StaticDatabases, SEPARATOR } from "../db/constants"
|
||||
import { getTenantId } from "../context"
|
||||
|
||||
export const getGlobalDBName = (tenantId?: string) => {
|
||||
// tenant ID can be set externally, for example user API where
|
||||
// new tenants are being created, this may be the case
|
||||
if (!tenantId) {
|
||||
tenantId = getTenantId()
|
||||
}
|
||||
return baseGlobalDBName(tenantId)
|
||||
}
|
||||
|
||||
export const baseGlobalDBName = (tenantId: string | undefined | null) => {
|
||||
let dbName
|
||||
if (!tenantId || tenantId === DEFAULT_TENANT_ID) {
|
||||
dbName = StaticDatabases.GLOBAL.name
|
||||
} else {
|
||||
dbName = `${tenantId}${SEPARATOR}${StaticDatabases.GLOBAL.name}`
|
||||
}
|
||||
return dbName
|
||||
}
|
|
@ -1377,6 +1377,11 @@ bcrypt@5.0.1:
|
|||
"@mapbox/node-pre-gyp" "^1.0.0"
|
||||
node-addon-api "^3.1.0"
|
||||
|
||||
bcryptjs@2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
|
||||
integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==
|
||||
|
||||
binary-extensions@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/bbui",
|
||||
"description": "A UI solution used in the different Budibase projects.",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"module": "dist/bbui.es.js",
|
||||
|
@ -38,7 +38,7 @@
|
|||
],
|
||||
"dependencies": {
|
||||
"@adobe/spectrum-css-workflow-icons": "^1.2.1",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "^1.3.18",
|
||||
"@spectrum-css/actionbutton": "^1.0.1",
|
||||
"@spectrum-css/actiongroup": "^1.0.1",
|
||||
"@spectrum-css/avatar": "^3.0.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/builder",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
@ -69,10 +69,10 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.15-alpha.9",
|
||||
"@budibase/client": "1.3.15-alpha.9",
|
||||
"@budibase/frontend-core": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/bbui": "^1.3.18",
|
||||
"@budibase/client": "^1.3.18",
|
||||
"@budibase/frontend-core": "^1.3.18",
|
||||
"@budibase/string-templates": "^1.3.18",
|
||||
"@sentry/browser": "5.19.1",
|
||||
"@spectrum-css/page": "^3.0.1",
|
||||
"@spectrum-css/vars": "^3.0.1",
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
type="string"
|
||||
{bindings}
|
||||
fillWidth={true}
|
||||
allowJS={false}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
"dataprovider",
|
||||
"repeater",
|
||||
"table",
|
||||
"dynamicfilter"
|
||||
"dynamicfilter",
|
||||
"daterangepicker"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -60,7 +61,6 @@
|
|||
"booleanfield",
|
||||
"longformfield",
|
||||
"attachmentfield",
|
||||
"daterangepicker",
|
||||
"jsonfield",
|
||||
"relationshipfield",
|
||||
"datetimefield",
|
||||
|
@ -80,5 +80,4 @@
|
|||
"donut"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
]
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/cli",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase CLI, for developers, self hosting and migrations.",
|
||||
"main": "src/index.js",
|
||||
"bin": {
|
||||
|
@ -26,9 +26,9 @@
|
|||
"outputPath": "build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/types": "1.3.15-alpha.9",
|
||||
"@budibase/backend-core": "1.3.18",
|
||||
"@budibase/string-templates": "1.3.18",
|
||||
"@budibase/types": "1.3.18",
|
||||
"axios": "0.21.2",
|
||||
"chalk": "4.1.0",
|
||||
"cli-progress": "3.11.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/client",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"license": "MPL-2.0",
|
||||
"module": "dist/budibase-client.js",
|
||||
"main": "dist/budibase-client.js",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"dev:builder": "rollup -cw"
|
||||
},
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.15-alpha.9",
|
||||
"@budibase/frontend-core": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/bbui": "^1.3.18",
|
||||
"@budibase/frontend-core": "^1.3.18",
|
||||
"@budibase/string-templates": "^1.3.18",
|
||||
"@spectrum-css/button": "^3.0.3",
|
||||
"@spectrum-css/card": "^3.0.3",
|
||||
"@spectrum-css/divider": "^1.0.3",
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@budibase/frontend-core",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase frontend core libraries used in builder and client",
|
||||
"author": "Budibase",
|
||||
"license": "MPL-2.0",
|
||||
"svelte": "src/index.js",
|
||||
"dependencies": {
|
||||
"@budibase/bbui": "1.3.15-alpha.9",
|
||||
"@budibase/bbui": "^1.3.18",
|
||||
"lodash": "^4.17.21",
|
||||
"svelte": "^3.46.2"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/server",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase Web Server",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -77,11 +77,11 @@
|
|||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@budibase/backend-core": "1.3.15-alpha.9",
|
||||
"@budibase/client": "1.3.15-alpha.9",
|
||||
"@budibase/pro": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/types": "1.3.15-alpha.9",
|
||||
"@budibase/backend-core": "^1.3.18",
|
||||
"@budibase/client": "^1.3.18",
|
||||
"@budibase/pro": "1.3.18",
|
||||
"@budibase/string-templates": "^1.3.18",
|
||||
"@budibase/types": "^1.3.18",
|
||||
"@bull-board/api": "3.7.0",
|
||||
"@bull-board/koa": "3.9.4",
|
||||
"@elastic/elasticsearch": "7.10.0",
|
||||
|
|
|
@ -371,7 +371,10 @@ module External {
|
|||
const toColumn = `${linkedTable.name}.${relationship.to}`
|
||||
// this is important when working with multiple relationships
|
||||
// between the same tables, don't want to overlap/multiply the relations
|
||||
if (!relationship.through && row[fromColumn] !== row[toColumn]) {
|
||||
if (
|
||||
!relationship.through &&
|
||||
row[fromColumn]?.toString() !== row[toColumn]?.toString()
|
||||
) {
|
||||
continue
|
||||
}
|
||||
let linked = basicProcessing(row, linkedTable)
|
||||
|
|
|
@ -37,8 +37,8 @@ function parseIntSafe(number) {
|
|||
let inThread = false
|
||||
|
||||
module.exports = {
|
||||
// important
|
||||
PORT: process.env.PORT || process.env.APP_PORT,
|
||||
// important - prefer app port to generic port
|
||||
PORT: process.env.APP_PORT || process.env.PORT,
|
||||
JWT_SECRET: process.env.JWT_SECRET,
|
||||
COUCH_DB_URL: process.env.COUCH_DB_URL,
|
||||
MINIO_URL: process.env.MINIO_URL,
|
||||
|
|
|
@ -49,7 +49,15 @@ const DATASOURCE_PATH = join(budibaseTempDir(), "datasource")
|
|||
exports.init = () => {
|
||||
const tempDir = budibaseTempDir()
|
||||
if (!fs.existsSync(tempDir)) {
|
||||
fs.mkdirSync(tempDir)
|
||||
// some test cases fire this quickly enough that
|
||||
// synchronous cases can end up here at the same time
|
||||
try {
|
||||
fs.mkdirSync(tempDir)
|
||||
} catch (err) {
|
||||
if (!err || err.code !== "EEXIST") {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
const clientLibPath = join(budibaseTempDir(), "budibase-client.js")
|
||||
if (env.isTest() && !fs.existsSync(clientLibPath)) {
|
||||
|
|
|
@ -1094,17 +1094,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.15-alpha.9.tgz#06c582d1aac93ba689a9738ea35939ccc5bac430"
|
||||
integrity sha512-uShQQVPE2EsfPY6BNZnl/yKQoR8VwJyiIfCNE/EYl5aIVvhrqva+vA7JeYAs4sf/vf8Y5kkZaJGzfvzEws4dHg==
|
||||
"@budibase/backend-core@1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.18.tgz#5ef26e3283f46b321103766b0359ca72035c8942"
|
||||
integrity sha512-utux5ydlnejKavU2H2HlCJkIyymVmGj+rVJp+SR1JrtPW2wkzHzpYn2k9eXFOYnAwqTF8jpCj4FVOEeDTfQcbw==
|
||||
dependencies:
|
||||
"@budibase/types" "1.3.15-alpha.9"
|
||||
"@budibase/types" "^1.3.18"
|
||||
"@shopify/jest-koa-mocks" "5.0.1"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-sdk "2.1030.0"
|
||||
bcrypt "5.0.1"
|
||||
bcryptjs "2.4.3"
|
||||
dotenv "16.0.1"
|
||||
emitter-listener "1.1.2"
|
||||
ioredis "4.28.0"
|
||||
|
@ -1180,13 +1179,13 @@
|
|||
svelte-flatpickr "^3.2.3"
|
||||
svelte-portal "^1.0.0"
|
||||
|
||||
"@budibase/pro@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.15-alpha.9.tgz#cb0ab3041df4c412eed9a8c7950f20ca0e3b62c5"
|
||||
integrity sha512-1eE7O/bYeHxSoG8V61B2OZN3bGD44RAinAFJLHvBK7ncHZSTOOH4fe5HLvFiWPm0gV5ONDHpqr9W5Vs6ZBXukQ==
|
||||
"@budibase/pro@1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.18.tgz#35a59e86c00971dd77a0b196e381a5ffd3be767c"
|
||||
integrity sha512-aFGUr/ut4Ki56qLSdFaDLoEIPmwMqT5dGmY1xBT3Bwvhoq7hXevk1bcPFGj0rWBJnYG9zg/jmik9V4mE/lUOag==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "1.3.15-alpha.9"
|
||||
"@budibase/types" "1.3.15-alpha.9"
|
||||
"@budibase/backend-core" "1.3.18"
|
||||
"@budibase/types" "1.3.18"
|
||||
"@koa/router" "8.0.8"
|
||||
joi "17.6.0"
|
||||
node-fetch "^2.6.1"
|
||||
|
@ -1209,10 +1208,10 @@
|
|||
svelte-apexcharts "^1.0.2"
|
||||
svelte-flatpickr "^3.1.0"
|
||||
|
||||
"@budibase/types@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.15-alpha.9.tgz#443cab0ca757a37af7a45f99caac35643fe273e5"
|
||||
integrity sha512-r1Z2PLPF3nR/bGzVyZ0/6RcOYb4Csmk4J/b1KJ57wzTeDdsRwgVgGO6QS+XYdwZctsKDNOm9FvpIQj3tNM8Rjw==
|
||||
"@budibase/types@1.3.18", "@budibase/types@^1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.18.tgz#cd65213f476a2f37065796d0ccba18c8e8e07504"
|
||||
integrity sha512-bMtS2RbbI3Ztl5aAwEVlsK+2PQ0vRSZm8n6YDRjC9Arc94B4GDl/sqowRndKYqVtUeA/gVW0HH8x+qzhuMX6Dw==
|
||||
|
||||
"@bull-board/api@3.7.0":
|
||||
version "3.7.0"
|
||||
|
@ -2325,6 +2324,11 @@
|
|||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@socket.io/component-emitter@~3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553"
|
||||
integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==
|
||||
|
||||
"@spectrum-css/actionbutton@^1.0.1":
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.1.14.tgz#4e12eb7f482fb5944c3d97547591964baebeb1d4"
|
||||
|
@ -2676,11 +2680,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
|
||||
integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==
|
||||
|
||||
"@types/component-emitter@^1.2.10":
|
||||
version "1.2.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506"
|
||||
integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ==
|
||||
|
||||
"@types/connect@*":
|
||||
version "3.4.35"
|
||||
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
|
||||
|
@ -2927,9 +2926,9 @@
|
|||
integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==
|
||||
|
||||
"@types/node@>=10.0.0":
|
||||
version "18.7.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.6.tgz#31743bc5772b6ac223845e18c3fc26f042713c83"
|
||||
integrity sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==
|
||||
version "18.7.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154"
|
||||
integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==
|
||||
|
||||
"@types/node@>=8.0.0 <15":
|
||||
version "14.18.21"
|
||||
|
@ -4800,7 +4799,7 @@ commoner@^0.10.1:
|
|||
q "^1.1.2"
|
||||
recast "^0.11.17"
|
||||
|
||||
component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@~1.3.0:
|
||||
component-emitter@^1.2.0, component-emitter@^1.2.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
|
@ -12849,26 +12848,25 @@ socket.io-adapter@~2.4.0:
|
|||
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6"
|
||||
integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==
|
||||
|
||||
socket.io-parser@~4.0.4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.5.tgz#cb404382c32324cc962f27f3a44058cf6e0552df"
|
||||
integrity sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==
|
||||
socket.io-parser@~4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.1.tgz#01c96efa11ded938dcb21cbe590c26af5eff65e5"
|
||||
integrity sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==
|
||||
dependencies:
|
||||
"@types/component-emitter" "^1.2.10"
|
||||
component-emitter "~1.3.0"
|
||||
"@socket.io/component-emitter" "~3.1.0"
|
||||
debug "~4.3.1"
|
||||
|
||||
socket.io@^4.5.1:
|
||||
version "4.5.1"
|
||||
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.1.tgz#aa7e73f8a6ce20ee3c54b2446d321bbb6b1a9029"
|
||||
integrity sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ==
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.2.tgz#1eb25fd380ab3d63470aa8279f8e48d922d443ac"
|
||||
integrity sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==
|
||||
dependencies:
|
||||
accepts "~1.3.4"
|
||||
base64id "~2.0.0"
|
||||
debug "~4.3.2"
|
||||
engine.io "~6.2.0"
|
||||
socket.io-adapter "~2.4.0"
|
||||
socket.io-parser "~4.0.4"
|
||||
socket.io-parser "~4.2.0"
|
||||
|
||||
sonic-boom@^1.0.2:
|
||||
version "1.4.1"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/string-templates",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Handlebars wrapper for Budibase templating.",
|
||||
"main": "src/index.cjs",
|
||||
"module": "dist/bundle.mjs",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@budibase/types",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase types",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
|
|
@ -7,3 +7,12 @@ export interface PlatformUserByEmail extends Document {
|
|||
tenantId: string
|
||||
userId: string
|
||||
}
|
||||
|
||||
/**
|
||||
* doc id is userId
|
||||
*/
|
||||
export interface PlatformUserById extends Document {
|
||||
tenantId: string
|
||||
}
|
||||
|
||||
export type PlatformUser = PlatformUserByEmail | PlatformUserById
|
||||
|
|
|
@ -47,6 +47,7 @@ export enum MigrationName {
|
|||
EVENT_GLOBAL_BACKFILL = "event_global_backfill",
|
||||
EVENT_INSTALLATION_BACKFILL = "event_installation_backfill",
|
||||
GLOBAL_INFO_SYNC_USERS = "global_info_sync_users",
|
||||
PLATFORM_USERS_EMAIL_CASING = "platform_users_email_casing",
|
||||
}
|
||||
|
||||
export interface MigrationDefinition {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@budibase/worker",
|
||||
"email": "hi@budibase.com",
|
||||
"version": "1.3.15-alpha.9",
|
||||
"version": "1.3.18",
|
||||
"description": "Budibase background service",
|
||||
"main": "src/index.ts",
|
||||
"repository": {
|
||||
|
@ -23,6 +23,7 @@
|
|||
"dev:stack:init": "node ./scripts/dev/manage.js init",
|
||||
"dev:builder": "npm run dev:stack:init && nodemon",
|
||||
"test": "jest --runInBand",
|
||||
"test:watch": "jest --watch",
|
||||
"env:multi:enable": "node scripts/multiTenancy.js enable",
|
||||
"env:multi:disable": "node scripts/multiTenancy.js disable",
|
||||
"env:selfhost:enable": "node scripts/selfhost.js enable",
|
||||
|
@ -35,10 +36,10 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"@budibase/backend-core": "1.3.15-alpha.9",
|
||||
"@budibase/pro": "1.3.15-alpha.9",
|
||||
"@budibase/string-templates": "1.3.15-alpha.9",
|
||||
"@budibase/types": "1.3.15-alpha.9",
|
||||
"@budibase/backend-core": "^1.3.18",
|
||||
"@budibase/pro": "1.3.18",
|
||||
"@budibase/string-templates": "^1.3.18",
|
||||
"@budibase/types": "^1.3.18",
|
||||
"@koa/router": "8.0.8",
|
||||
"@sentry/node": "6.17.7",
|
||||
"@techpass/passport-openidconnect": "0.3.2",
|
||||
|
|
|
@ -242,6 +242,26 @@ describe("/api/global/users", () => {
|
|||
expect(response.body.message).toBe(`Unavailable`)
|
||||
expect(events.user.created).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it("should not be able to create a user with the same email and different casing", async () => {
|
||||
const user = structures.users.user()
|
||||
await api.users.saveUser(user)
|
||||
|
||||
user.email = user.email.toUpperCase()
|
||||
await api.users.saveUser(user, 400)
|
||||
|
||||
expect(events.user.created).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should not be able to bulk create a user with the same email and different casing", async () => {
|
||||
const user = structures.users.user()
|
||||
await api.users.saveUser(user)
|
||||
|
||||
user.email = user.email.toUpperCase()
|
||||
await api.users.bulkCreateUsers([user])
|
||||
|
||||
expect(events.user.created).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", () => {
|
||||
|
|
|
@ -43,7 +43,8 @@ const env = {
|
|||
PLATFORM_URL: process.env.PLATFORM_URL,
|
||||
APPS_URL: process.env.APPS_URL,
|
||||
// ports
|
||||
PORT: process.env.PORT || process.env.WORKER_PORT,
|
||||
// prefer worker port to generic port
|
||||
PORT: process.env.WORKER_PORT || process.env.PORT,
|
||||
CLUSTER_PORT: process.env.CLUSTER_PORT,
|
||||
// flags
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
|
|
|
@ -278,39 +278,61 @@ export const addTenant = async (
|
|||
}
|
||||
|
||||
const getExistingTenantUsers = async (emails: string[]): Promise<User[]> => {
|
||||
return dbUtils.queryGlobalView(ViewName.USER_BY_EMAIL, {
|
||||
keys: emails,
|
||||
const lcEmails = emails.map(email => email.toLowerCase())
|
||||
const params = {
|
||||
keys: lcEmails,
|
||||
include_docs: true,
|
||||
}
|
||||
|
||||
const opts = {
|
||||
arrayResponse: true,
|
||||
})
|
||||
}
|
||||
|
||||
return dbUtils.queryGlobalView(
|
||||
ViewName.USER_BY_EMAIL,
|
||||
params,
|
||||
undefined,
|
||||
opts
|
||||
) as Promise<User[]>
|
||||
}
|
||||
|
||||
const getExistingPlatformUsers = async (
|
||||
emails: string[]
|
||||
): Promise<PlatformUserByEmail[]> => {
|
||||
return dbUtils.doWithDB(
|
||||
StaticDatabases.PLATFORM_INFO.name,
|
||||
async (infoDb: any) => {
|
||||
const response: AllDocsResponse<PlatformUserByEmail> =
|
||||
await infoDb.allDocs({
|
||||
keys: emails,
|
||||
include_docs: true,
|
||||
})
|
||||
return response.rows
|
||||
.filter(row => row.doc && (row.error !== "not_found") !== null)
|
||||
.map((row: any) => row.doc)
|
||||
}
|
||||
)
|
||||
const lcEmails = emails.map(email => email.toLowerCase())
|
||||
const params = {
|
||||
keys: lcEmails,
|
||||
include_docs: true,
|
||||
}
|
||||
|
||||
const opts = {
|
||||
arrayResponse: true,
|
||||
}
|
||||
return dbUtils.queryPlatformView(
|
||||
ViewName.PLATFORM_USERS_LOWERCASE,
|
||||
params,
|
||||
opts
|
||||
) as Promise<PlatformUserByEmail[]>
|
||||
}
|
||||
|
||||
const getExistingAccounts = async (
|
||||
emails: string[]
|
||||
): Promise<AccountMetadata[]> => {
|
||||
return dbUtils.queryPlatformView(ViewName.ACCOUNT_BY_EMAIL, {
|
||||
keys: emails,
|
||||
const lcEmails = emails.map(email => email.toLowerCase())
|
||||
const params = {
|
||||
keys: lcEmails,
|
||||
include_docs: true,
|
||||
}
|
||||
|
||||
const opts = {
|
||||
arrayResponse: true,
|
||||
})
|
||||
}
|
||||
|
||||
return dbUtils.queryPlatformView(
|
||||
ViewName.ACCOUNT_BY_EMAIL,
|
||||
params,
|
||||
opts
|
||||
) as Promise<AccountMetadata[]>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,7 +354,7 @@ const searchExistingEmails = async (emails: string[]) => {
|
|||
const existingAccounts = await getExistingAccounts(emails)
|
||||
matchedEmails.push(...existingAccounts.map(account => account.email))
|
||||
|
||||
return [...new Set(matchedEmails)]
|
||||
return [...new Set(matchedEmails.map(email => email.toLowerCase()))]
|
||||
}
|
||||
|
||||
export const bulkCreate = async (
|
||||
|
@ -351,8 +373,10 @@ export const bulkCreate = async (
|
|||
|
||||
for (const newUser of newUsersRequested) {
|
||||
if (
|
||||
newUsers.find((x: any) => x.email === newUser.email) ||
|
||||
existingEmails.includes(newUser.email)
|
||||
newUsers.find(
|
||||
(x: User) => x.email.toLowerCase() === newUser.email.toLowerCase()
|
||||
) ||
|
||||
existingEmails.includes(newUser.email.toLowerCase())
|
||||
) {
|
||||
unsuccessful.push({
|
||||
email: newUser.email,
|
||||
|
|
|
@ -291,17 +291,16 @@
|
|||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||
|
||||
"@budibase/backend-core@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.15-alpha.9.tgz#06c582d1aac93ba689a9738ea35939ccc5bac430"
|
||||
integrity sha512-uShQQVPE2EsfPY6BNZnl/yKQoR8VwJyiIfCNE/EYl5aIVvhrqva+vA7JeYAs4sf/vf8Y5kkZaJGzfvzEws4dHg==
|
||||
"@budibase/backend-core@1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.3.18.tgz#5ef26e3283f46b321103766b0359ca72035c8942"
|
||||
integrity sha512-utux5ydlnejKavU2H2HlCJkIyymVmGj+rVJp+SR1JrtPW2wkzHzpYn2k9eXFOYnAwqTF8jpCj4FVOEeDTfQcbw==
|
||||
dependencies:
|
||||
"@budibase/types" "1.3.15-alpha.9"
|
||||
"@budibase/types" "^1.3.18"
|
||||
"@shopify/jest-koa-mocks" "5.0.1"
|
||||
"@techpass/passport-openidconnect" "0.3.2"
|
||||
aws-sdk "2.1030.0"
|
||||
bcrypt "5.0.1"
|
||||
bcryptjs "2.4.3"
|
||||
dotenv "16.0.1"
|
||||
emitter-listener "1.1.2"
|
||||
ioredis "4.28.0"
|
||||
|
@ -327,21 +326,21 @@
|
|||
uuid "8.3.2"
|
||||
zlib "1.0.5"
|
||||
|
||||
"@budibase/pro@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.15-alpha.9.tgz#cb0ab3041df4c412eed9a8c7950f20ca0e3b62c5"
|
||||
integrity sha512-1eE7O/bYeHxSoG8V61B2OZN3bGD44RAinAFJLHvBK7ncHZSTOOH4fe5HLvFiWPm0gV5ONDHpqr9W5Vs6ZBXukQ==
|
||||
"@budibase/pro@1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.3.18.tgz#35a59e86c00971dd77a0b196e381a5ffd3be767c"
|
||||
integrity sha512-aFGUr/ut4Ki56qLSdFaDLoEIPmwMqT5dGmY1xBT3Bwvhoq7hXevk1bcPFGj0rWBJnYG9zg/jmik9V4mE/lUOag==
|
||||
dependencies:
|
||||
"@budibase/backend-core" "1.3.15-alpha.9"
|
||||
"@budibase/types" "1.3.15-alpha.9"
|
||||
"@budibase/backend-core" "1.3.18"
|
||||
"@budibase/types" "1.3.18"
|
||||
"@koa/router" "8.0.8"
|
||||
joi "17.6.0"
|
||||
node-fetch "^2.6.1"
|
||||
|
||||
"@budibase/types@1.3.15-alpha.9":
|
||||
version "1.3.15-alpha.9"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.15-alpha.9.tgz#443cab0ca757a37af7a45f99caac35643fe273e5"
|
||||
integrity sha512-r1Z2PLPF3nR/bGzVyZ0/6RcOYb4Csmk4J/b1KJ57wzTeDdsRwgVgGO6QS+XYdwZctsKDNOm9FvpIQj3tNM8Rjw==
|
||||
"@budibase/types@1.3.18", "@budibase/types@^1.3.18":
|
||||
version "1.3.18"
|
||||
resolved "https://registry.yarnpkg.com/@budibase/types/-/types-1.3.18.tgz#cd65213f476a2f37065796d0ccba18c8e8e07504"
|
||||
integrity sha512-bMtS2RbbI3Ztl5aAwEVlsK+2PQ0vRSZm8n6YDRjC9Arc94B4GDl/sqowRndKYqVtUeA/gVW0HH8x+qzhuMX6Dw==
|
||||
|
||||
"@cspotcode/source-map-consumer@0.8.0":
|
||||
version "0.8.0"
|
||||
|
|
Loading…
Reference in New Issue