diff --git a/packages/server/src/utilities/budibaseDir.js b/packages/server/src/utilities/budibaseDir.js deleted file mode 100644 index dc992aaa8c..0000000000 --- a/packages/server/src/utilities/budibaseDir.js +++ /dev/null @@ -1,3 +0,0 @@ -const { budibaseTempDir } = require("@budibase/backend-core/objectStore") - -module.exports.budibaseTempDir = budibaseTempDir diff --git a/packages/server/src/utilities/budibaseDir.ts b/packages/server/src/utilities/budibaseDir.ts new file mode 100644 index 0000000000..bee92ab7b4 --- /dev/null +++ b/packages/server/src/utilities/budibaseDir.ts @@ -0,0 +1,3 @@ +import { objectStore } from "@budibase/backend-core" + +export const budibaseTempDir = objectStore.budibaseTempDir diff --git a/packages/server/src/utilities/redis.js b/packages/server/src/utilities/redis.ts similarity index 55% rename from packages/server/src/utilities/redis.js rename to packages/server/src/utilities/redis.ts index b39b7cae55..8659843dbb 100644 --- a/packages/server/src/utilities/redis.js +++ b/packages/server/src/utilities/redis.ts @@ -1,46 +1,47 @@ -const { Client, utils } = require("@budibase/backend-core/redis") -const { getGlobalIDFromUserMetadataID } = require("../db/utils") +import { redis } from "@budibase/backend-core" +import { getGlobalIDFromUserMetadataID } from "../db/utils" +import { User } from "@budibase/types" const APP_DEV_LOCK_SECONDS = 600 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 // reduces the performance hit -exports.init = async () => { - devAppClient = new Client(utils.Databases.DEV_LOCKS) - debounceClient = new Client(utils.Databases.DEBOUNCE) - flagClient = new Client(utils.Databases.FLAGS) +export async function init() { + devAppClient = new redis.Client(redis.utils.Databases.DEV_LOCKS) + debounceClient = new redis.Client(redis.utils.Databases.DEBOUNCE) + flagClient = new redis.Client(redis.utils.Databases.FLAGS) await devAppClient.init() await debounceClient.init() await flagClient.init() } -exports.shutdown = async () => { +export async function shutdown() { if (devAppClient) await devAppClient.finish() if (debounceClient) await debounceClient.finish() if (flagClient) await flagClient.finish() console.log("Redis shutdown") } -exports.doesUserHaveLock = async (devAppId, user) => { +export async function doesUserHaveLock(devAppId: string, user: User) { const value = await devAppClient.get(devAppId) if (!value) { return true } // make sure both IDs are global const expected = getGlobalIDFromUserMetadataID(value._id) - const userId = getGlobalIDFromUserMetadataID(user._id) + const userId = getGlobalIDFromUserMetadataID(user._id!) return expected === userId } -exports.getLocksById = async appIds => { +export async function getLocksById(appIds: string[]) { return await devAppClient.bulkGet(appIds) } -exports.updateLock = async (devAppId, user) => { +export async function updateLock(devAppId: string, user: User) { // make sure always global user ID - const globalId = getGlobalIDFromUserMetadataID(user._id) + const globalId = getGlobalIDFromUserMetadataID(user._id!) const inputUser = { ...user, userId: globalId, @@ -51,35 +52,35 @@ exports.updateLock = async (devAppId, user) => { 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) if (!value) { return } - const userId = getGlobalIDFromUserMetadataID(user._id) + const userId = getGlobalIDFromUserMetadataID(user._id!) if (value._id !== userId) { throw "User does not hold lock, cannot clear it." } await devAppClient.delete(devAppId) } -exports.checkDebounce = async id => { +export async function checkDebounce(id: string) { return debounceClient.get(id) } -exports.setDebounce = async (id, seconds) => { +export async function setDebounce(id: string, seconds: number) { 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) } -exports.checkTestFlag = async id => { +export async function checkTestFlag(id: string) { const flag = await flagClient.get(id) return !!(flag && flag.testing) } -exports.clearTestFlag = async id => { +export async function clearTestFlag(id: string) { await devAppClient.delete(id) } diff --git a/packages/server/src/utilities/routing/index.js b/packages/server/src/utilities/routing/index.js deleted file mode 100644 index 963119130b..0000000000 --- a/packages/server/src/utilities/routing/index.js +++ /dev/null @@ -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 diff --git a/packages/server/src/utilities/routing/index.ts b/packages/server/src/utilities/routing/index.ts new file mode 100644 index 0000000000..de966a946b --- /dev/null +++ b/packages/server/src/utilities/routing/index.ts @@ -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 { + const db = context.getAppDB() + try { + const allRouting = await db.query( + 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 + } + } +} diff --git a/packages/server/src/utilities/usageQuota/rows.js b/packages/server/src/utilities/usageQuota/rows.ts similarity index 71% rename from packages/server/src/utilities/usageQuota/rows.js rename to packages/server/src/utilities/usageQuota/rows.ts index 0a92507a96..1bc7c8897d 100644 --- a/packages/server/src/utilities/usageQuota/rows.js +++ b/packages/server/src/utilities/usageQuota/rows.ts @@ -1,23 +1,19 @@ -const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils") -const { - isDevAppID, - getDevelopmentAppID, - getProdAppID, - doWithDB, -} = require("@budibase/backend-core/db") +import { getRowParams, USER_METDATA_PREFIX } from "../../db/utils" +import { db as dbCore } from "@budibase/backend-core" +import { Database, Row } from "@budibase/types" const ROW_EXCLUSIONS = [USER_METDATA_PREFIX] -const getAppPairs = appIds => { +function getAppPairs(appIds: string[]) { // collect the app ids into dev / prod pairs // keyed by the dev app id - const pairs = {} + const pairs: { [key: string]: { devId?: string; prodId?: string } } = {} for (let appId of appIds) { - const devId = getDevelopmentAppID(appId) + const devId = dbCore.getDevelopmentAppID(appId) if (!pairs[devId]) { pairs[devId] = {} } - if (isDevAppID(appId)) { + if (dbCore.isDevAppID(appId)) { pairs[devId].devId = appId } else { pairs[devId].prodId = appId @@ -26,9 +22,9 @@ const getAppPairs = appIds => { 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 - return doWithDB(appId, async db => { + return dbCore.doWithDB(appId, async (db: Database) => { const response = await db.allDocs( getRowParams(null, null, { include_docs: false, @@ -52,13 +48,13 @@ const getAppRows = async appId => { * 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. */ -exports.getUniqueRows = async appIds => { - let uniqueRows = [], - rowsByApp = {} +export async function getUniqueRows(appIds: string[]) { + let uniqueRows: Row[] = [], + rowsByApp: { [key: string]: Row[] } = {} const pairs = getAppPairs(appIds) for (let pair of Object.values(pairs)) { - let appRows = [] + let appRows: Row[] = [] for (let appId of [pair.devId, pair.prodId]) { if (!appId) { continue @@ -75,7 +71,7 @@ exports.getUniqueRows = async appIds => { // this can't be done on all rows because app import results in // duplicate row ids across apps // 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)] uniqueRows = uniqueRows.concat(rowsByApp[prodId]) } diff --git a/packages/server/src/utilities/workerRequests.js b/packages/server/src/utilities/workerRequests.ts similarity index 66% rename from packages/server/src/utilities/workerRequests.js rename to packages/server/src/utilities/workerRequests.ts index e606ba9fa6..b5554bbe6f 100644 --- a/packages/server/src/utilities/workerRequests.js +++ b/packages/server/src/utilities/workerRequests.ts @@ -1,19 +1,18 @@ -const fetch = require("node-fetch") -const env = require("../environment") -const { checkSlashesInUrl } = require("./index") -const { getProdAppID } = require("@budibase/backend-core/db") -const { updateAppRole } = require("./global") -const { Header } = require("@budibase/backend-core/constants") -const { getTenantId, isTenantIdSet } = require("@budibase/backend-core/tenancy") +import fetch from "node-fetch" +import env from "../environment" +import { checkSlashesInUrl } from "./index" +import { db as dbCore, constants, tenancy } from "@budibase/backend-core" +import { updateAppRole } from "./global" +import { BBContext, Automation } from "@budibase/types" -function request(ctx, request) { +export function request(ctx?: BBContext, request?: any) { if (!request.headers) { request.headers = {} } if (!ctx) { - request.headers[Header.API_KEY] = env.INTERNAL_API_KEY - if (isTenantIdSet()) { - request.headers[Header.TENANT_ID] = getTenantId() + request.headers[constants.Header.API_KEY] = env.INTERNAL_API_KEY + if (tenancy.isTenantIdSet()) { + request.headers[constants.Header.TENANT_ID] = tenancy.getTenantId() } } if (request.body && Object.keys(request.body).length > 0) { @@ -31,7 +30,11 @@ function request(ctx, request) { return request } -async function checkResponse(response, errorMsg, { ctx } = {}) { +async function checkResponse( + response: any, + errorMsg: string, + { ctx }: { ctx?: BBContext } = {} +) { if (response.status !== 200) { let error try { @@ -51,22 +54,20 @@ async function checkResponse(response, errorMsg, { ctx } = {}) { return response.json() } -exports.request = request - // have to pass in the tenant ID as this could be coming from an automation -exports.sendSmtpEmail = async ( - to, - from, - subject, - contents, - cc, - bcc, - automation -) => { +export async function sendSmtpEmail( + to: string, + from: string, + subject: string, + contents: string, + cc: string, + bcc: string, + automation: Automation +) { // tenant ID will be set in header const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/email/send`), - request(null, { + request(undefined, { method: "POST", body: { email: to, @@ -83,7 +84,7 @@ exports.sendSmtpEmail = async ( 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 response = await fetch( checkSlashesInUrl(env.WORKER_URL + endpoint), @@ -97,8 +98,8 @@ exports.getGlobalSelf = async (ctx, appId = null) => { return json } -exports.removeAppFromUserRoles = async (ctx, appId) => { - const prodAppId = getProdAppID(appId) +export async function removeAppFromUserRoles(ctx: BBContext, appId: string) { + const prodAppId = dbCore.getProdAppID(appId) const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/roles/${prodAppId}`), request(ctx, { @@ -108,7 +109,7 @@ exports.removeAppFromUserRoles = async (ctx, appId) => { return checkResponse(response, "remove app role") } -exports.allGlobalUsers = async ctx => { +export async function allGlobalUsers(ctx: BBContext) { const response = await fetch( checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), // 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 }) } -exports.saveGlobalUser = async ctx => { +export async function saveGlobalUser(ctx: BBContext) { const response = await fetch( checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), // 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 }) } -exports.deleteGlobalUser = async ctx => { +export async function deleteGlobalUser(ctx: BBContext) { const response = await fetch( checkSlashesInUrl( 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 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( checkSlashesInUrl( env.WORKER_URL + `/api/global/users/${ctx.params.userId}` @@ -148,26 +149,30 @@ exports.readGlobalUser = async 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( 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") } -exports.getChecklist = async () => { +export async function getChecklist() { const response = await fetch( checkSlashesInUrl(env.WORKER_URL + "/api/global/configs/checklist"), - request(null, { method: "GET" }) + request(undefined, { method: "GET" }) ) return checkResponse(response, "get checklist") } -exports.generateApiKey = async userId => { +export async function generateApiKey(userId: string) { const response = await fetch( 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") } diff --git a/packages/types/src/documents/app/screen.ts b/packages/types/src/documents/app/screen.ts index 6390c3b18c..a3778d140f 100644 --- a/packages/types/src/documents/app/screen.ts +++ b/packages/types/src/documents/app/screen.ts @@ -12,14 +12,16 @@ export interface ScreenProps extends Document { hAlign?: string } +export interface ScreenRouting { + route: string + roleId: string + homeScreen?: boolean +} + export interface Screen extends Document { layoutId?: string showNavigation?: boolean width?: string - routing: { - route: string - roleId: string - homeScreen?: boolean - } + routing: ScreenRouting props: ScreenProps } diff --git a/packages/types/src/documents/pouch.ts b/packages/types/src/documents/pouch.ts index 8ad4ace5b7..d484f4700d 100644 --- a/packages/types/src/documents/pouch.ts +++ b/packages/types/src/documents/pouch.ts @@ -7,7 +7,7 @@ export interface RowResponse { id: string key: string error: string - value: RowValue + value: T | RowValue doc?: T | any }