More Typescript conversion, as part of backend-core importing improvements.

This commit is contained in:
mike12345567 2022-11-22 12:41:36 +00:00
parent 51471449fc
commit a74225cd1e
9 changed files with 121 additions and 110 deletions

View File

@ -1,3 +0,0 @@
const { budibaseTempDir } = require("@budibase/backend-core/objectStore")
module.exports.budibaseTempDir = budibaseTempDir

View File

@ -0,0 +1,3 @@
import { objectStore } from "@budibase/backend-core"
export const budibaseTempDir = objectStore.budibaseTempDir

View File

@ -1,46 +1,47 @@
const { Client, utils } = require("@budibase/backend-core/redis") import { redis } from "@budibase/backend-core"
const { getGlobalIDFromUserMetadataID } = require("../db/utils") import { getGlobalIDFromUserMetadataID } from "../db/utils"
import { User } from "@budibase/types"
const APP_DEV_LOCK_SECONDS = 600 const APP_DEV_LOCK_SECONDS = 600
const AUTOMATION_TEST_FLAG_SECONDS = 60 const AUTOMATION_TEST_FLAG_SECONDS = 60
let devAppClient, debounceClient, flagClient let devAppClient: any, debounceClient: any, flagClient: any
// we init this as we want to keep the connection open all the time // we init this as we want to keep the connection open all the time
// reduces the performance hit // reduces the performance hit
exports.init = async () => { export async function init() {
devAppClient = new Client(utils.Databases.DEV_LOCKS) devAppClient = new redis.Client(redis.utils.Databases.DEV_LOCKS)
debounceClient = new Client(utils.Databases.DEBOUNCE) debounceClient = new redis.Client(redis.utils.Databases.DEBOUNCE)
flagClient = new Client(utils.Databases.FLAGS) flagClient = new redis.Client(redis.utils.Databases.FLAGS)
await devAppClient.init() await devAppClient.init()
await debounceClient.init() await debounceClient.init()
await flagClient.init() await flagClient.init()
} }
exports.shutdown = async () => { export async function shutdown() {
if (devAppClient) await devAppClient.finish() if (devAppClient) await devAppClient.finish()
if (debounceClient) await debounceClient.finish() if (debounceClient) await debounceClient.finish()
if (flagClient) await flagClient.finish() if (flagClient) await flagClient.finish()
console.log("Redis shutdown") console.log("Redis shutdown")
} }
exports.doesUserHaveLock = async (devAppId, user) => { export async function doesUserHaveLock(devAppId: string, user: User) {
const value = await devAppClient.get(devAppId) const value = await devAppClient.get(devAppId)
if (!value) { if (!value) {
return true return true
} }
// make sure both IDs are global // make sure both IDs are global
const expected = getGlobalIDFromUserMetadataID(value._id) const expected = getGlobalIDFromUserMetadataID(value._id)
const userId = getGlobalIDFromUserMetadataID(user._id) const userId = getGlobalIDFromUserMetadataID(user._id!)
return expected === userId return expected === userId
} }
exports.getLocksById = async appIds => { export async function getLocksById(appIds: string[]) {
return await devAppClient.bulkGet(appIds) return await devAppClient.bulkGet(appIds)
} }
exports.updateLock = async (devAppId, user) => { export async function updateLock(devAppId: string, user: User) {
// make sure always global user ID // make sure always global user ID
const globalId = getGlobalIDFromUserMetadataID(user._id) const globalId = getGlobalIDFromUserMetadataID(user._id!)
const inputUser = { const inputUser = {
...user, ...user,
userId: globalId, userId: globalId,
@ -51,35 +52,35 @@ exports.updateLock = async (devAppId, user) => {
await devAppClient.store(devAppId, inputUser, APP_DEV_LOCK_SECONDS) await devAppClient.store(devAppId, inputUser, APP_DEV_LOCK_SECONDS)
} }
exports.clearLock = async (devAppId, user) => { export async function clearLock(devAppId: string, user: User) {
const value = await devAppClient.get(devAppId) const value = await devAppClient.get(devAppId)
if (!value) { if (!value) {
return return
} }
const userId = getGlobalIDFromUserMetadataID(user._id) const userId = getGlobalIDFromUserMetadataID(user._id!)
if (value._id !== userId) { if (value._id !== userId) {
throw "User does not hold lock, cannot clear it." throw "User does not hold lock, cannot clear it."
} }
await devAppClient.delete(devAppId) await devAppClient.delete(devAppId)
} }
exports.checkDebounce = async id => { export async function checkDebounce(id: string) {
return debounceClient.get(id) return debounceClient.get(id)
} }
exports.setDebounce = async (id, seconds) => { export async function setDebounce(id: string, seconds: number) {
await debounceClient.store(id, "debouncing", seconds) await debounceClient.store(id, "debouncing", seconds)
} }
exports.setTestFlag = async id => { export async function setTestFlag(id: string) {
await flagClient.store(id, { testing: true }, AUTOMATION_TEST_FLAG_SECONDS) await flagClient.store(id, { testing: true }, AUTOMATION_TEST_FLAG_SECONDS)
} }
exports.checkTestFlag = async id => { export async function checkTestFlag(id: string) {
const flag = await flagClient.get(id) const flag = await flagClient.get(id)
return !!(flag && flag.testing) return !!(flag && flag.testing)
} }
exports.clearTestFlag = async id => { export async function clearTestFlag(id: string) {
await devAppClient.delete(id) await devAppClient.delete(id)
} }

View File

@ -1,25 +0,0 @@
const { createRoutingView } = require("../../db/views/staticViews")
const { ViewName, getQueryIndex, UNICODE_MAX } = require("../../db/utils")
const { getAppDB } = require("@budibase/backend-core/context")
exports.getRoutingInfo = async () => {
const db = getAppDB()
try {
const allRouting = await db.query(getQueryIndex(ViewName.ROUTING), {
startKey: "",
endKey: UNICODE_MAX,
})
return allRouting.rows.map(row => row.value)
} catch (err) {
// check if the view doesn't exist, it should for all new instances
/* istanbul ignore next */
if (err != null && err.name === "not_found") {
await createRoutingView()
return exports.getRoutingInfo()
} else {
throw err
}
}
}
exports.createRoutingView = createRoutingView

View File

@ -0,0 +1,32 @@
import { createRoutingView } from "../../db/views/staticViews"
import { ViewName, getQueryIndex, UNICODE_MAX } from "../../db/utils"
import { context } from "@budibase/backend-core"
import { ScreenRouting } from "@budibase/types"
type ScreenRoutesView = {
id: string
routing: ScreenRouting
}
export async function getRoutingInfo(): Promise<ScreenRoutesView[]> {
const db = context.getAppDB()
try {
const allRouting = await db.query<ScreenRoutesView>(
getQueryIndex(ViewName.ROUTING),
{
startkey: "",
endkey: UNICODE_MAX,
}
)
return allRouting.rows.map(row => row.value as ScreenRoutesView)
} catch (err: any) {
// check if the view doesn't exist, it should for all new instances
/* istanbul ignore next */
if (err != null && err.name === "not_found") {
await createRoutingView()
return getRoutingInfo()
} else {
throw err
}
}
}

View File

@ -1,23 +1,19 @@
const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils") import { getRowParams, USER_METDATA_PREFIX } from "../../db/utils"
const { import { db as dbCore } from "@budibase/backend-core"
isDevAppID, import { Database, Row } from "@budibase/types"
getDevelopmentAppID,
getProdAppID,
doWithDB,
} = require("@budibase/backend-core/db")
const ROW_EXCLUSIONS = [USER_METDATA_PREFIX] const ROW_EXCLUSIONS = [USER_METDATA_PREFIX]
const getAppPairs = appIds => { function getAppPairs(appIds: string[]) {
// collect the app ids into dev / prod pairs // collect the app ids into dev / prod pairs
// keyed by the dev app id // keyed by the dev app id
const pairs = {} const pairs: { [key: string]: { devId?: string; prodId?: string } } = {}
for (let appId of appIds) { for (let appId of appIds) {
const devId = getDevelopmentAppID(appId) const devId = dbCore.getDevelopmentAppID(appId)
if (!pairs[devId]) { if (!pairs[devId]) {
pairs[devId] = {} pairs[devId] = {}
} }
if (isDevAppID(appId)) { if (dbCore.isDevAppID(appId)) {
pairs[devId].devId = appId pairs[devId].devId = appId
} else { } else {
pairs[devId].prodId = appId pairs[devId].prodId = appId
@ -26,9 +22,9 @@ const getAppPairs = appIds => {
return pairs return pairs
} }
const getAppRows = async appId => { async function getAppRows(appId: string) {
// need to specify the app ID, as this is used for different apps in one call // need to specify the app ID, as this is used for different apps in one call
return doWithDB(appId, async db => { return dbCore.doWithDB(appId, async (db: Database) => {
const response = await db.allDocs( const response = await db.allDocs(
getRowParams(null, null, { getRowParams(null, null, {
include_docs: false, include_docs: false,
@ -52,13 +48,13 @@ const getAppRows = async appId => {
* The returned rows will be unique on a per dev/prod app basis. * The returned rows will be unique on a per dev/prod app basis.
* Rows duplicates may exist across apps due to data import so they are not filtered out. * Rows duplicates may exist across apps due to data import so they are not filtered out.
*/ */
exports.getUniqueRows = async appIds => { export async function getUniqueRows(appIds: string[]) {
let uniqueRows = [], let uniqueRows: Row[] = [],
rowsByApp = {} rowsByApp: { [key: string]: Row[] } = {}
const pairs = getAppPairs(appIds) const pairs = getAppPairs(appIds)
for (let pair of Object.values(pairs)) { for (let pair of Object.values(pairs)) {
let appRows = [] let appRows: Row[] = []
for (let appId of [pair.devId, pair.prodId]) { for (let appId of [pair.devId, pair.prodId]) {
if (!appId) { if (!appId) {
continue continue
@ -75,7 +71,7 @@ exports.getUniqueRows = async appIds => {
// this can't be done on all rows because app import results in // this can't be done on all rows because app import results in
// duplicate row ids across apps // duplicate row ids across apps
// the array pre-concat is important to avoid stack overflow // the array pre-concat is important to avoid stack overflow
const prodId = getProdAppID(pair.devId || pair.prodId) const prodId = dbCore.getProdAppID((pair.devId || pair.prodId)!)
rowsByApp[prodId] = [...new Set(appRows)] rowsByApp[prodId] = [...new Set(appRows)]
uniqueRows = uniqueRows.concat(rowsByApp[prodId]) uniqueRows = uniqueRows.concat(rowsByApp[prodId])
} }

View File

@ -1,19 +1,18 @@
const fetch = require("node-fetch") import fetch from "node-fetch"
const env = require("../environment") import env from "../environment"
const { checkSlashesInUrl } = require("./index") import { checkSlashesInUrl } from "./index"
const { getProdAppID } = require("@budibase/backend-core/db") import { db as dbCore, constants, tenancy } from "@budibase/backend-core"
const { updateAppRole } = require("./global") import { updateAppRole } from "./global"
const { Header } = require("@budibase/backend-core/constants") import { BBContext, Automation } from "@budibase/types"
const { getTenantId, isTenantIdSet } = require("@budibase/backend-core/tenancy")
function request(ctx, request) { export function request(ctx?: BBContext, request?: any) {
if (!request.headers) { if (!request.headers) {
request.headers = {} request.headers = {}
} }
if (!ctx) { if (!ctx) {
request.headers[Header.API_KEY] = env.INTERNAL_API_KEY request.headers[constants.Header.API_KEY] = env.INTERNAL_API_KEY
if (isTenantIdSet()) { if (tenancy.isTenantIdSet()) {
request.headers[Header.TENANT_ID] = getTenantId() request.headers[constants.Header.TENANT_ID] = tenancy.getTenantId()
} }
} }
if (request.body && Object.keys(request.body).length > 0) { if (request.body && Object.keys(request.body).length > 0) {
@ -31,7 +30,11 @@ function request(ctx, request) {
return request return request
} }
async function checkResponse(response, errorMsg, { ctx } = {}) { async function checkResponse(
response: any,
errorMsg: string,
{ ctx }: { ctx?: BBContext } = {}
) {
if (response.status !== 200) { if (response.status !== 200) {
let error let error
try { try {
@ -51,22 +54,20 @@ async function checkResponse(response, errorMsg, { ctx } = {}) {
return response.json() return response.json()
} }
exports.request = request
// have to pass in the tenant ID as this could be coming from an automation // have to pass in the tenant ID as this could be coming from an automation
exports.sendSmtpEmail = async ( export async function sendSmtpEmail(
to, to: string,
from, from: string,
subject, subject: string,
contents, contents: string,
cc, cc: string,
bcc, bcc: string,
automation automation: Automation
) => { ) {
// tenant ID will be set in header // tenant ID will be set in header
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`), checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`),
request(null, { request(undefined, {
method: "POST", method: "POST",
body: { body: {
email: to, email: to,
@ -83,7 +84,7 @@ exports.sendSmtpEmail = async (
return checkResponse(response, "send email") return checkResponse(response, "send email")
} }
exports.getGlobalSelf = async (ctx, appId = null) => { export async function getGlobalSelf(ctx: BBContext, appId?: string) {
const endpoint = `/api/global/self` const endpoint = `/api/global/self`
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + endpoint), checkSlashesInUrl(env.WORKER_URL + endpoint),
@ -97,8 +98,8 @@ exports.getGlobalSelf = async (ctx, appId = null) => {
return json return json
} }
exports.removeAppFromUserRoles = async (ctx, appId) => { export async function removeAppFromUserRoles(ctx: BBContext, appId: string) {
const prodAppId = getProdAppID(appId) const prodAppId = dbCore.getProdAppID(appId)
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + `/api/global/roles/${prodAppId}`), checkSlashesInUrl(env.WORKER_URL + `/api/global/roles/${prodAppId}`),
request(ctx, { request(ctx, {
@ -108,7 +109,7 @@ exports.removeAppFromUserRoles = async (ctx, appId) => {
return checkResponse(response, "remove app role") return checkResponse(response, "remove app role")
} }
exports.allGlobalUsers = async ctx => { export async function allGlobalUsers(ctx: BBContext) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), checkSlashesInUrl(env.WORKER_URL + "/api/global/users"),
// we don't want to use API key when getting self // we don't want to use API key when getting self
@ -117,7 +118,7 @@ exports.allGlobalUsers = async ctx => {
return checkResponse(response, "get users", { ctx }) return checkResponse(response, "get users", { ctx })
} }
exports.saveGlobalUser = async ctx => { export async function saveGlobalUser(ctx: BBContext) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), checkSlashesInUrl(env.WORKER_URL + "/api/global/users"),
// we don't want to use API key when getting self // we don't want to use API key when getting self
@ -126,7 +127,7 @@ exports.saveGlobalUser = async ctx => {
return checkResponse(response, "save user", { ctx }) return checkResponse(response, "save user", { ctx })
} }
exports.deleteGlobalUser = async ctx => { export async function deleteGlobalUser(ctx: BBContext) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl( checkSlashesInUrl(
env.WORKER_URL + `/api/global/users/${ctx.params.userId}` env.WORKER_URL + `/api/global/users/${ctx.params.userId}`
@ -134,10 +135,10 @@ exports.deleteGlobalUser = async ctx => {
// we don't want to use API key when getting self // we don't want to use API key when getting self
request(ctx, { method: "DELETE" }) request(ctx, { method: "DELETE" })
) )
return checkResponse(response, "delete user", { ctx, body: ctx.request.body }) return checkResponse(response, "delete user", { ctx })
} }
exports.readGlobalUser = async ctx => { export async function readGlobalUser(ctx: BBContext) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl( checkSlashesInUrl(
env.WORKER_URL + `/api/global/users/${ctx.params.userId}` env.WORKER_URL + `/api/global/users/${ctx.params.userId}`
@ -148,26 +149,30 @@ exports.readGlobalUser = async ctx => {
return checkResponse(response, "get user", { ctx }) return checkResponse(response, "get user", { ctx })
} }
exports.createAdminUser = async (email, password, tenantId) => { export async function createAdminUser(
email: string,
password: string,
tenantId: string
) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + "/api/global/users/init"), checkSlashesInUrl(env.WORKER_URL + "/api/global/users/init"),
request(null, { method: "POST", body: { email, password, tenantId } }) request(undefined, { method: "POST", body: { email, password, tenantId } })
) )
return checkResponse(response, "create admin user") return checkResponse(response, "create admin user")
} }
exports.getChecklist = async () => { export async function getChecklist() {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + "/api/global/configs/checklist"), checkSlashesInUrl(env.WORKER_URL + "/api/global/configs/checklist"),
request(null, { method: "GET" }) request(undefined, { method: "GET" })
) )
return checkResponse(response, "get checklist") return checkResponse(response, "get checklist")
} }
exports.generateApiKey = async userId => { export async function generateApiKey(userId: string) {
const response = await fetch( const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + "/api/global/self/api_key"), checkSlashesInUrl(env.WORKER_URL + "/api/global/self/api_key"),
request(null, { method: "POST", body: { userId } }) request(undefined, { method: "POST", body: { userId } })
) )
return checkResponse(response, "generate API key") return checkResponse(response, "generate API key")
} }

View File

@ -12,14 +12,16 @@ export interface ScreenProps extends Document {
hAlign?: string hAlign?: string
} }
export interface ScreenRouting {
route: string
roleId: string
homeScreen?: boolean
}
export interface Screen extends Document { export interface Screen extends Document {
layoutId?: string layoutId?: string
showNavigation?: boolean showNavigation?: boolean
width?: string width?: string
routing: { routing: ScreenRouting
route: string
roleId: string
homeScreen?: boolean
}
props: ScreenProps props: ScreenProps
} }

View File

@ -7,7 +7,7 @@ export interface RowResponse<T> {
id: string id: string
key: string key: string
error: string error: string
value: RowValue value: T | RowValue
doc?: T | any doc?: T | any
} }