Some server typescript re-writes, only automations left and some controllers.
This commit is contained in:
parent
a38d617138
commit
0c73662f32
|
@ -1,7 +1,5 @@
|
|||
import {
|
||||
createTempFolder,
|
||||
downloadTarballDirect,
|
||||
} from "../../../utilities/fileSystem"
|
||||
import { createTempFolder } from "../../../utilities/fileSystem"
|
||||
import { objectStore } from "@budibase/backend-core"
|
||||
|
||||
export async function downloadUnzipTarball(
|
||||
url: string,
|
||||
|
@ -10,7 +8,7 @@ export async function downloadUnzipTarball(
|
|||
) {
|
||||
try {
|
||||
const path = createTempFolder(name)
|
||||
await downloadTarballDirect(url, path, headers)
|
||||
await objectStore.downloadTarballDirect(url, path, headers)
|
||||
|
||||
return path
|
||||
} catch (e: any) {
|
||||
|
|
|
@ -14,7 +14,6 @@ const {
|
|||
} = require("../../../utilities/fileSystem")
|
||||
const env = require("../../../environment")
|
||||
const { clientLibraryPath } = require("../../../utilities")
|
||||
const { upload, deleteFiles } = require("../../../utilities/fileSystem")
|
||||
const { attachmentsRelativeURL } = require("../../../utilities")
|
||||
const { DocumentType } = require("../../../db/utils")
|
||||
const { context, objectStore, utils } = require("@budibase/backend-core")
|
||||
|
@ -22,7 +21,7 @@ const AWS = require("aws-sdk")
|
|||
const fs = require("fs")
|
||||
|
||||
async function prepareUpload({ s3Key, bucket, metadata, file }: any) {
|
||||
const response = await upload({
|
||||
const response = await objectStore.upload({
|
||||
bucket,
|
||||
metadata,
|
||||
filename: s3Key,
|
||||
|
@ -95,7 +94,10 @@ export const uploadFile = async function (ctx: any) {
|
|||
}
|
||||
|
||||
export const deleteObjects = async function (ctx: any) {
|
||||
ctx.body = await deleteFiles(ObjectStoreBuckets.APPS, ctx.request.body.keys)
|
||||
ctx.body = await objectStore.deleteFiles(
|
||||
ObjectStoreBuckets.APPS,
|
||||
ctx.request.body.keys
|
||||
)
|
||||
}
|
||||
|
||||
export const serveApp = async function (ctx: any) {
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
const { objectStore, roles, constants } = require("@budibase/backend-core")
|
||||
|
||||
const FilterTypes = {
|
||||
STRING: "string",
|
||||
FUZZY: "fuzzy",
|
||||
RANGE: "range",
|
||||
EQUAL: "equal",
|
||||
NOT_EQUAL: "notEqual",
|
||||
EMPTY: "empty",
|
||||
NOT_EMPTY: "notEmpty",
|
||||
CONTAINS: "contains",
|
||||
NOT_CONTAINS: "notContains",
|
||||
ONE_OF: "oneOf",
|
||||
}
|
||||
|
||||
exports.FilterTypes = FilterTypes
|
||||
exports.NoEmptyFilterStrings = [
|
||||
FilterTypes.STRING,
|
||||
FilterTypes.FUZZY,
|
||||
FilterTypes.EQUAL,
|
||||
FilterTypes.NOT_EQUAL,
|
||||
FilterTypes.CONTAINS,
|
||||
FilterTypes.NOT_CONTAINS,
|
||||
]
|
||||
|
||||
exports.FieldTypes = {
|
||||
STRING: "string",
|
||||
BARCODEQR: "barcodeqr",
|
||||
LONGFORM: "longform",
|
||||
OPTIONS: "options",
|
||||
NUMBER: "number",
|
||||
BOOLEAN: "boolean",
|
||||
ARRAY: "array",
|
||||
DATETIME: "datetime",
|
||||
ATTACHMENT: "attachment",
|
||||
LINK: "link",
|
||||
FORMULA: "formula",
|
||||
AUTO: "auto",
|
||||
JSON: "json",
|
||||
INTERNAL: "internal",
|
||||
}
|
||||
|
||||
exports.CanSwitchTypes = [
|
||||
[exports.FieldTypes.JSON, exports.FieldTypes.ARRAY],
|
||||
[
|
||||
exports.FieldTypes.STRING,
|
||||
exports.FieldTypes.OPTIONS,
|
||||
exports.FieldTypes.LONGFORM,
|
||||
exports.FieldTypes.BARCODEQR,
|
||||
],
|
||||
[exports.FieldTypes.BOOLEAN, exports.FieldTypes.NUMBER],
|
||||
]
|
||||
|
||||
exports.SwitchableTypes = exports.CanSwitchTypes.reduce((prev, current) =>
|
||||
prev ? prev.concat(current) : current
|
||||
)
|
||||
|
||||
exports.RelationshipTypes = {
|
||||
ONE_TO_MANY: "one-to-many",
|
||||
MANY_TO_ONE: "many-to-one",
|
||||
MANY_TO_MANY: "many-to-many",
|
||||
}
|
||||
|
||||
exports.FormulaTypes = {
|
||||
STATIC: "static",
|
||||
DYNAMIC: "dynamic",
|
||||
}
|
||||
|
||||
exports.AuthTypes = {
|
||||
APP: "app",
|
||||
BUILDER: "builder",
|
||||
EXTERNAL: "external",
|
||||
}
|
||||
|
||||
exports.DataSourceOperation = {
|
||||
CREATE: "CREATE",
|
||||
READ: "READ",
|
||||
UPDATE: "UPDATE",
|
||||
DELETE: "DELETE",
|
||||
BULK_CREATE: "BULK_CREATE",
|
||||
CREATE_TABLE: "CREATE_TABLE",
|
||||
UPDATE_TABLE: "UPDATE_TABLE",
|
||||
DELETE_TABLE: "DELETE_TABLE",
|
||||
}
|
||||
|
||||
exports.DatasourceAuthTypes = {
|
||||
GOOGLE: "google",
|
||||
}
|
||||
|
||||
exports.SortDirection = {
|
||||
ASCENDING: "ASCENDING",
|
||||
DESCENDING: "DESCENDING",
|
||||
}
|
||||
|
||||
exports.USERS_TABLE_SCHEMA = {
|
||||
_id: "ta_users",
|
||||
type: "table",
|
||||
views: {},
|
||||
name: "Users",
|
||||
// TODO: ADMIN PANEL - when implemented this doesn't need to be carried out
|
||||
schema: {
|
||||
email: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
email: true,
|
||||
length: {
|
||||
maximum: "",
|
||||
},
|
||||
presence: true,
|
||||
},
|
||||
fieldName: "email",
|
||||
name: "email",
|
||||
},
|
||||
firstName: {
|
||||
name: "firstName",
|
||||
fieldName: "firstName",
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
lastName: {
|
||||
name: "lastName",
|
||||
fieldName: "lastName",
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
roleId: {
|
||||
fieldName: "roleId",
|
||||
name: "roleId",
|
||||
type: exports.FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
inclusion: Object.values(roles.BUILTIN_ROLE_IDS),
|
||||
},
|
||||
},
|
||||
status: {
|
||||
fieldName: "status",
|
||||
name: "status",
|
||||
type: exports.FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
inclusion: Object.values(constants.UserStatus),
|
||||
},
|
||||
},
|
||||
},
|
||||
primaryDisplay: "email",
|
||||
}
|
||||
|
||||
exports.AutoFieldSubTypes = {
|
||||
CREATED_BY: "createdBy",
|
||||
CREATED_AT: "createdAt",
|
||||
UPDATED_BY: "updatedBy",
|
||||
UPDATED_AT: "updatedAt",
|
||||
AUTO_ID: "autoID",
|
||||
}
|
||||
|
||||
exports.AutoFieldDefaultNames = {
|
||||
CREATED_BY: "Created By",
|
||||
CREATED_AT: "Created At",
|
||||
UPDATED_BY: "Updated By",
|
||||
UPDATED_AT: "Updated At",
|
||||
AUTO_ID: "Auto ID",
|
||||
}
|
||||
|
||||
exports.OBJ_STORE_DIRECTORY = "/prod-budi-app-assets"
|
||||
exports.BaseQueryVerbs = {
|
||||
CREATE: "create",
|
||||
READ: "read",
|
||||
UPDATE: "update",
|
||||
DELETE: "delete",
|
||||
}
|
||||
|
||||
exports.MetadataTypes = {
|
||||
AUTOMATION_TEST_INPUT: "automationTestInput",
|
||||
AUTOMATION_TEST_HISTORY: "automationTestHistory",
|
||||
}
|
||||
|
||||
exports.InvalidColumns = {
|
||||
ID: "_id",
|
||||
REV: "_rev",
|
||||
TABLE_ID: "tableId",
|
||||
}
|
||||
|
||||
exports.BuildSchemaErrors = {
|
||||
NO_KEY: "no_key",
|
||||
INVALID_COLUMN: "invalid_column",
|
||||
}
|
||||
|
||||
exports.AutomationErrors = {
|
||||
INCORRECT_TYPE: "INCORRECT_TYPE",
|
||||
MAX_ITERATIONS: "MAX_ITERATIONS_REACHED",
|
||||
FAILURE_CONDITION: "FAILURE_CONDITION_MET",
|
||||
}
|
||||
|
||||
// pass through the list from the auth/core lib
|
||||
exports.ObjectStoreBuckets = objectStore.ObjectStoreBuckets
|
||||
|
||||
exports.MAX_AUTOMATION_RECURRING_ERRORS = 5
|
|
@ -0,0 +1,204 @@
|
|||
import { objectStore, roles, constants } from "@budibase/backend-core"
|
||||
|
||||
export enum FilterTypes {
|
||||
STRING = "string",
|
||||
FUZZY = "fuzzy",
|
||||
RANGE = "range",
|
||||
EQUAL = "equal",
|
||||
NOT_EQUAL = "notEqual",
|
||||
EMPTY = "empty",
|
||||
NOT_EMPTY = "notEmpty",
|
||||
CONTAINS = "contains",
|
||||
NOT_CONTAINS = "notContains",
|
||||
ONE_OF = "oneOf",
|
||||
}
|
||||
|
||||
export const NoEmptyFilterStrings = [
|
||||
FilterTypes.STRING,
|
||||
FilterTypes.FUZZY,
|
||||
FilterTypes.EQUAL,
|
||||
FilterTypes.NOT_EQUAL,
|
||||
FilterTypes.CONTAINS,
|
||||
FilterTypes.NOT_CONTAINS,
|
||||
]
|
||||
|
||||
export enum FieldTypes {
|
||||
STRING = "string",
|
||||
BARCODEQR = "barcodeqr",
|
||||
LONGFORM = "longform",
|
||||
OPTIONS = "options",
|
||||
NUMBER = "number",
|
||||
BOOLEAN = "boolean",
|
||||
ARRAY = "array",
|
||||
DATETIME = "datetime",
|
||||
ATTACHMENT = "attachment",
|
||||
LINK = "link",
|
||||
FORMULA = "formula",
|
||||
AUTO = "auto",
|
||||
JSON = "json",
|
||||
INTERNAL = "internal",
|
||||
}
|
||||
|
||||
export const CanSwitchTypes = [
|
||||
[exports.FieldTypes.JSON, exports.FieldTypes.ARRAY],
|
||||
[
|
||||
exports.FieldTypes.STRING,
|
||||
exports.FieldTypes.OPTIONS,
|
||||
exports.FieldTypes.LONGFORM,
|
||||
exports.FieldTypes.BARCODEQR,
|
||||
],
|
||||
[exports.FieldTypes.BOOLEAN, exports.FieldTypes.NUMBER],
|
||||
]
|
||||
|
||||
export const SwitchableTypes = CanSwitchTypes.reduce((prev, current) =>
|
||||
prev ? prev.concat(current) : current
|
||||
)
|
||||
|
||||
export enum RelationshipTypes {
|
||||
ONE_TO_MANY = "one-to-many",
|
||||
MANY_TO_ONE = "many-to-one",
|
||||
MANY_TO_MANY = "many-to-many",
|
||||
}
|
||||
|
||||
export enum FormulaTypes {
|
||||
STATIC = "static",
|
||||
DYNAMIC = "dynamic",
|
||||
}
|
||||
|
||||
export enum AuthTypes {
|
||||
APP = "app",
|
||||
BUILDER = "builder",
|
||||
EXTERNAL = "external",
|
||||
}
|
||||
|
||||
export enum DataSourceOperation {
|
||||
CREATE = "CREATE",
|
||||
READ = "READ",
|
||||
UPDATE = "UPDATE",
|
||||
DELETE = "DELETE",
|
||||
BULK_CREATE = "BULK_CREATE",
|
||||
CREATE_TABLE = "CREATE_TABLE",
|
||||
UPDATE_TABLE = "UPDATE_TABLE",
|
||||
DELETE_TABLE = "DELETE_TABLE",
|
||||
}
|
||||
|
||||
export enum DatasourceAuthTypes {
|
||||
GOOGLE = "google",
|
||||
}
|
||||
|
||||
export enum SortDirection {
|
||||
ASCENDING = "ASCENDING",
|
||||
DESCENDING = "DESCENDING",
|
||||
}
|
||||
|
||||
export const USERS_TABLE_SCHEMA = {
|
||||
_id: "ta_users",
|
||||
type: "table",
|
||||
views: {},
|
||||
name: "Users",
|
||||
// TODO: ADMIN PANEL - when implemented this doesn't need to be carried out
|
||||
schema: {
|
||||
email: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
email: true,
|
||||
length: {
|
||||
maximum: "",
|
||||
},
|
||||
presence: true,
|
||||
},
|
||||
fieldName: "email",
|
||||
name: "email",
|
||||
},
|
||||
firstName: {
|
||||
name: "firstName",
|
||||
fieldName: "firstName",
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
lastName: {
|
||||
name: "lastName",
|
||||
fieldName: "lastName",
|
||||
type: exports.FieldTypes.STRING,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
},
|
||||
},
|
||||
roleId: {
|
||||
fieldName: "roleId",
|
||||
name: "roleId",
|
||||
type: exports.FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
inclusion: Object.values(roles.BUILTIN_ROLE_IDS),
|
||||
},
|
||||
},
|
||||
status: {
|
||||
fieldName: "status",
|
||||
name: "status",
|
||||
type: exports.FieldTypes.OPTIONS,
|
||||
constraints: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
presence: false,
|
||||
inclusion: Object.values(constants.UserStatus),
|
||||
},
|
||||
},
|
||||
},
|
||||
primaryDisplay: "email",
|
||||
}
|
||||
|
||||
export enum AutoFieldSubTypes {
|
||||
CREATED_BY = "createdBy",
|
||||
CREATED_AT = "createdAt",
|
||||
UPDATED_BY = "updatedBy",
|
||||
UPDATED_AT = "updatedAt",
|
||||
AUTO_ID = "autoID",
|
||||
}
|
||||
|
||||
export enum AutoFieldDefaultNames {
|
||||
CREATED_BY = "Created By",
|
||||
CREATED_AT = "Created At",
|
||||
UPDATED_BY = "Updated By",
|
||||
UPDATED_AT = "Updated At",
|
||||
AUTO_ID = "Auto ID",
|
||||
}
|
||||
|
||||
export const OBJ_STORE_DIRECTORY = "/prod-budi-app-assets"
|
||||
export enum BaseQueryVerbs {
|
||||
CREATE = "create",
|
||||
READ = "read",
|
||||
UPDATE = "update",
|
||||
DELETE = "delete",
|
||||
}
|
||||
|
||||
export enum MetadataTypes {
|
||||
AUTOMATION_TEST_INPUT = "automationTestInput",
|
||||
AUTOMATION_TEST_HISTORY = "automationTestHistory",
|
||||
}
|
||||
|
||||
export enum InvalidColumns {
|
||||
ID = "_id",
|
||||
REV = "_rev",
|
||||
TABLE_ID = "tableId",
|
||||
}
|
||||
|
||||
export enum BuildSchemaErrors {
|
||||
NO_KEY = "no_key",
|
||||
INVALID_COLUMN = "invalid_column",
|
||||
}
|
||||
|
||||
export enum AutomationErrors {
|
||||
INCORRECT_TYPE = "INCORRECT_TYPE",
|
||||
MAX_ITERATIONS = "MAX_ITERATIONS_REACHED",
|
||||
FAILURE_CONDITION = "FAILURE_CONDITION_MET",
|
||||
}
|
||||
|
||||
// pass through the list from the auth/core lib
|
||||
export const ObjectStoreBuckets = objectStore.ObjectStoreBuckets
|
||||
export const MAX_AUTOMATION_RECURRING_ERRORS = 5
|
|
@ -1,9 +1,9 @@
|
|||
const BASE_LAYOUT_PROP_IDS = {
|
||||
export const BASE_LAYOUT_PROP_IDS = {
|
||||
PRIVATE: "layout_private_master",
|
||||
PUBLIC: "layout_public_master",
|
||||
}
|
||||
|
||||
const EMPTY_LAYOUT = {
|
||||
export const EMPTY_LAYOUT = {
|
||||
componentLibraries: ["@budibase/standard-components"],
|
||||
title: "{{ name }}",
|
||||
favicon: "./_shared/favicon.png",
|
||||
|
@ -48,7 +48,7 @@ const EMPTY_LAYOUT = {
|
|||
},
|
||||
}
|
||||
|
||||
const BASE_LAYOUTS = [
|
||||
export const BASE_LAYOUTS = [
|
||||
{
|
||||
_id: BASE_LAYOUT_PROP_IDS.PRIVATE,
|
||||
componentLibraries: ["@budibase/standard-components"],
|
||||
|
@ -145,9 +145,3 @@ const BASE_LAYOUTS = [
|
|||
},
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
BASE_LAYOUTS,
|
||||
BASE_LAYOUT_PROP_IDS,
|
||||
EMPTY_LAYOUT,
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
const { roles } = require("@budibase/backend-core")
|
||||
const { BASE_LAYOUT_PROP_IDS } = require("./layouts")
|
||||
|
||||
exports.createHomeScreen = () => ({
|
||||
description: "",
|
||||
url: "",
|
||||
layoutId: BASE_LAYOUT_PROP_IDS.PRIVATE,
|
||||
props: {
|
||||
_id: "d834fea2-1b3e-4320-ab34-f9009f5ecc59",
|
||||
_component: "@budibase/standard-components/container",
|
||||
_styles: {
|
||||
normal: {},
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
_transition: "fade",
|
||||
_children: [
|
||||
{
|
||||
_id: "ef60083f-4a02-4df3-80f3-a0d3d16847e7",
|
||||
_component: "@budibase/standard-components/heading",
|
||||
_styles: {
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
text: "Welcome to your Budibase App 👋",
|
||||
size: "M",
|
||||
align: "left",
|
||||
_instanceName: "Heading",
|
||||
_children: [],
|
||||
},
|
||||
],
|
||||
_instanceName: "Home",
|
||||
direction: "column",
|
||||
hAlign: "stretch",
|
||||
vAlign: "top",
|
||||
size: "grow",
|
||||
gap: "M",
|
||||
},
|
||||
routing: {
|
||||
route: "/",
|
||||
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
|
||||
},
|
||||
name: "home-screen",
|
||||
})
|
|
@ -0,0 +1,48 @@
|
|||
import { roles } from "@budibase/backend-core"
|
||||
import { BASE_LAYOUT_PROP_IDS } from "./layouts"
|
||||
|
||||
export function createHomeScreen() {
|
||||
return {
|
||||
description: "",
|
||||
url: "",
|
||||
layoutId: BASE_LAYOUT_PROP_IDS.PRIVATE,
|
||||
props: {
|
||||
_id: "d834fea2-1b3e-4320-ab34-f9009f5ecc59",
|
||||
_component: "@budibase/standard-components/container",
|
||||
_styles: {
|
||||
normal: {},
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
_transition: "fade",
|
||||
_children: [
|
||||
{
|
||||
_id: "ef60083f-4a02-4df3-80f3-a0d3d16847e7",
|
||||
_component: "@budibase/standard-components/heading",
|
||||
_styles: {
|
||||
hover: {},
|
||||
active: {},
|
||||
selected: {},
|
||||
},
|
||||
text: "Welcome to your Budibase App 👋",
|
||||
size: "M",
|
||||
align: "left",
|
||||
_instanceName: "Heading",
|
||||
_children: [],
|
||||
},
|
||||
],
|
||||
_instanceName: "Home",
|
||||
direction: "column",
|
||||
hAlign: "stretch",
|
||||
vAlign: "top",
|
||||
size: "grow",
|
||||
gap: "M",
|
||||
},
|
||||
routing: {
|
||||
route: "/",
|
||||
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
|
||||
},
|
||||
name: "home-screen",
|
||||
}
|
||||
}
|
|
@ -1,31 +1,32 @@
|
|||
const {
|
||||
import {
|
||||
FieldTypes,
|
||||
AutoFieldSubTypes,
|
||||
RelationshipTypes,
|
||||
} = require("../../constants/index")
|
||||
const { importToRows } = require("../../api/controllers/table/utils")
|
||||
const { cloneDeep } = require("lodash/fp")
|
||||
const LinkDocument = require("../linkedRows/LinkDocument")
|
||||
const { inventoryImport } = require("./inventoryImport")
|
||||
const { employeeImport } = require("./employeeImport")
|
||||
const { jobsImport } = require("./jobsImport")
|
||||
const { expensesImport } = require("./expensesImport")
|
||||
const { db: dbCore } = require("@budibase/backend-core")
|
||||
} from "../../constants"
|
||||
import { importToRows } from "../../api/controllers/table/utils"
|
||||
import { cloneDeep } from "lodash/fp"
|
||||
import LinkDocument from "../linkedRows/LinkDocument"
|
||||
import { inventoryImport } from "./inventoryImport"
|
||||
import { employeeImport } from "./employeeImport"
|
||||
import { jobsImport } from "./jobsImport"
|
||||
import { expensesImport } from "./expensesImport"
|
||||
import { db as dbCore } from "@budibase/backend-core"
|
||||
import { Table, Row } from "@budibase/types"
|
||||
|
||||
exports.DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs"
|
||||
exports.DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory"
|
||||
exports.DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses"
|
||||
exports.DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee"
|
||||
exports.DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default"
|
||||
exports.DEFAULT_BB_DATASOURCE = {
|
||||
_id: this.DEFAULT_BB_DATASOURCE_ID,
|
||||
export const DEFAULT_JOBS_TABLE_ID = "ta_bb_jobs"
|
||||
export const DEFAULT_INVENTORY_TABLE_ID = "ta_bb_inventory"
|
||||
export const DEFAULT_EXPENSES_TABLE_ID = "ta_bb_expenses"
|
||||
export const DEFAULT_EMPLOYEE_TABLE_ID = "ta_bb_employee"
|
||||
export const DEFAULT_BB_DATASOURCE_ID = "datasource_internal_bb_default"
|
||||
export const DEFAULT_BB_DATASOURCE = {
|
||||
_id: DEFAULT_BB_DATASOURCE_ID,
|
||||
type: dbCore.BUDIBASE_DATASOURCE_TYPE,
|
||||
name: "Sample Data",
|
||||
source: "BUDIBASE",
|
||||
config: {},
|
||||
}
|
||||
|
||||
const syncLastIds = (table, rowCount) => {
|
||||
function syncLastIds(table: Table, rowCount: number) {
|
||||
Object.keys(table.schema).forEach(key => {
|
||||
const entry = table.schema[key]
|
||||
if (entry.autocolumn && entry.subtype == "autoID") {
|
||||
|
@ -34,7 +35,7 @@ const syncLastIds = (table, rowCount) => {
|
|||
})
|
||||
}
|
||||
|
||||
const tableImport = (table, data) => {
|
||||
function tableImport(table: Table, data: Row) {
|
||||
const cloneTable = cloneDeep(table)
|
||||
const rowDocs = importToRows(data, cloneTable)
|
||||
syncLastIds(cloneTable, rowDocs.length)
|
||||
|
@ -77,11 +78,11 @@ const AUTO_COLUMNS = {
|
|||
},
|
||||
}
|
||||
|
||||
exports.DEFAULT_INVENTORY_TABLE_SCHEMA = {
|
||||
_id: this.DEFAULT_INVENTORY_TABLE_ID,
|
||||
export const DEFAULT_INVENTORY_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_INVENTORY_TABLE_ID,
|
||||
type: "internal",
|
||||
views: {},
|
||||
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
primaryDisplay: "Item Name",
|
||||
name: "Inventory",
|
||||
schema: {
|
||||
|
@ -186,12 +187,12 @@ exports.DEFAULT_INVENTORY_TABLE_SCHEMA = {
|
|||
},
|
||||
}
|
||||
|
||||
exports.DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
|
||||
_id: this.DEFAULT_EMPLOYEE_TABLE_ID,
|
||||
export const DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
|
||||
_id: DEFAULT_EMPLOYEE_TABLE_ID,
|
||||
type: "internal",
|
||||
views: {},
|
||||
name: "Employees",
|
||||
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
primaryDisplay: "First Name",
|
||||
schema: {
|
||||
"First Name": {
|
||||
|
@ -300,7 +301,7 @@ exports.DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
|
|||
fieldName: "Assigned",
|
||||
name: "Jobs",
|
||||
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
||||
tableId: this.DEFAULT_JOBS_TABLE_ID,
|
||||
tableId: DEFAULT_JOBS_TABLE_ID,
|
||||
},
|
||||
"Start Date": {
|
||||
type: FieldTypes.DATETIME,
|
||||
|
@ -334,11 +335,11 @@ exports.DEFAULT_EMPLOYEE_TABLE_SCHEMA = {
|
|||
},
|
||||
}
|
||||
|
||||
exports.DEFAULT_JOBS_TABLE_SCHEMA = {
|
||||
_id: this.DEFAULT_JOBS_TABLE_ID,
|
||||
export const DEFAULT_JOBS_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_JOBS_TABLE_ID,
|
||||
type: "internal",
|
||||
name: "Jobs",
|
||||
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
primaryDisplay: "Job ID",
|
||||
schema: {
|
||||
"Job ID": {
|
||||
|
@ -456,7 +457,7 @@ exports.DEFAULT_JOBS_TABLE_SCHEMA = {
|
|||
Assigned: {
|
||||
name: "Assigned",
|
||||
type: FieldTypes.LINK,
|
||||
tableId: this.DEFAULT_EMPLOYEE_TABLE_ID,
|
||||
tableId: DEFAULT_EMPLOYEE_TABLE_ID,
|
||||
fieldName: "Jobs",
|
||||
relationshipType: RelationshipTypes.MANY_TO_MANY,
|
||||
// sortable: true,
|
||||
|
@ -491,12 +492,12 @@ exports.DEFAULT_JOBS_TABLE_SCHEMA = {
|
|||
},
|
||||
}
|
||||
|
||||
exports.DEFAULT_EXPENSES_TABLE_SCHEMA = {
|
||||
_id: this.DEFAULT_EXPENSES_TABLE_ID,
|
||||
export const DEFAULT_EXPENSES_TABLE_SCHEMA: Table = {
|
||||
_id: DEFAULT_EXPENSES_TABLE_ID,
|
||||
type: "internal",
|
||||
views: {},
|
||||
name: "Expenses",
|
||||
sourceId: exports.DEFAULT_BB_DATASOURCE_ID,
|
||||
sourceId: DEFAULT_BB_DATASOURCE_ID,
|
||||
primaryDisplay: "Expense ID",
|
||||
schema: {
|
||||
"Expense ID": {
|
||||
|
@ -601,38 +602,40 @@ exports.DEFAULT_EXPENSES_TABLE_SCHEMA = {
|
|||
},
|
||||
}
|
||||
|
||||
exports.buildDefaultDocs = () => {
|
||||
export function buildDefaultDocs() {
|
||||
const inventoryData = tableImport(
|
||||
this.DEFAULT_INVENTORY_TABLE_SCHEMA,
|
||||
DEFAULT_INVENTORY_TABLE_SCHEMA,
|
||||
inventoryImport
|
||||
)
|
||||
|
||||
const employeeData = tableImport(
|
||||
this.DEFAULT_EMPLOYEE_TABLE_SCHEMA,
|
||||
DEFAULT_EMPLOYEE_TABLE_SCHEMA,
|
||||
employeeImport
|
||||
)
|
||||
|
||||
const jobData = tableImport(this.DEFAULT_JOBS_TABLE_SCHEMA, jobsImport)
|
||||
const jobData = tableImport(DEFAULT_JOBS_TABLE_SCHEMA, jobsImport)
|
||||
|
||||
const expensesData = tableImport(
|
||||
this.DEFAULT_EXPENSES_TABLE_SCHEMA,
|
||||
DEFAULT_EXPENSES_TABLE_SCHEMA,
|
||||
expensesImport
|
||||
)
|
||||
|
||||
// Build one link doc for each employee/job
|
||||
const jobEmployeeLinks = employeeData.rows.map((employee, index) => {
|
||||
return new LinkDocument(
|
||||
employeeData.table._id,
|
||||
"Jobs",
|
||||
employeeData.rows[index]._id,
|
||||
jobData.table._id,
|
||||
"Assigned",
|
||||
jobData.rows[index]._id
|
||||
)
|
||||
})
|
||||
const jobEmployeeLinks = employeeData.rows.map(
|
||||
(employee: any, index: any) => {
|
||||
return new LinkDocument(
|
||||
employeeData.table._id!,
|
||||
"Jobs",
|
||||
employeeData.rows[index]._id,
|
||||
jobData.table._id!,
|
||||
"Assigned",
|
||||
jobData.rows[index]._id
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
return [
|
||||
this.DEFAULT_BB_DATASOURCE,
|
||||
DEFAULT_BB_DATASOURCE,
|
||||
inventoryData.table,
|
||||
employeeData.table,
|
||||
jobData.table,
|
|
@ -1,4 +1,4 @@
|
|||
exports.employeeImport = [
|
||||
export const employeeImport = [
|
||||
{
|
||||
"First Name": "Julie",
|
||||
"Last Name": "Jimenez",
|
|
@ -1,4 +1,4 @@
|
|||
exports.expensesImport = [
|
||||
export const expensesImport = [
|
||||
{
|
||||
"Date Paid": "2022-11-12T12:00:00.000",
|
||||
"Payment Due": "2022-11-01T12:00:00.000",
|
|
@ -1,4 +1,4 @@
|
|||
exports.inventoryImport = [
|
||||
export const inventoryImport = [
|
||||
{
|
||||
Status: ["Available"],
|
||||
"Item Name": "Little Blue Van",
|
|
@ -1,4 +1,4 @@
|
|||
exports.jobsImport = [
|
||||
export const jobsImport = [
|
||||
{
|
||||
"Works End": "2023-01-28T12:00:00.000",
|
||||
"Customer Email": "susie.peterson@example.com",
|
|
@ -1,8 +1,7 @@
|
|||
let { merge } = require("lodash")
|
||||
let env = require("../environment")
|
||||
import { merge } from "lodash"
|
||||
import env from "../environment"
|
||||
|
||||
const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1"
|
||||
exports.AWS_REGION = AWS_REGION
|
||||
export const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1"
|
||||
|
||||
const TableInfo = {
|
||||
API_KEYS: {
|
||||
|
@ -16,10 +15,36 @@ const TableInfo = {
|
|||
},
|
||||
}
|
||||
|
||||
let docClient = null
|
||||
let docClient: any = null
|
||||
|
||||
type GetOpts = {
|
||||
primary: string
|
||||
sort?: string
|
||||
otherProps?: any
|
||||
}
|
||||
|
||||
type UpdateOpts = {
|
||||
primary: string
|
||||
sort?: string
|
||||
expression?: string
|
||||
condition?: string
|
||||
names?: string[]
|
||||
values?: any[]
|
||||
exists?: boolean
|
||||
otherProps?: any
|
||||
}
|
||||
|
||||
type PutOpts = {
|
||||
item: any
|
||||
otherProps?: any
|
||||
}
|
||||
|
||||
class Table {
|
||||
constructor(tableInfo) {
|
||||
_name: string
|
||||
_primary: string
|
||||
_sort?: string
|
||||
|
||||
constructor(tableInfo: { name: string; primary: string; sort?: string }) {
|
||||
if (!tableInfo.name || !tableInfo.primary) {
|
||||
throw "Table info must specify a name and a primary key"
|
||||
}
|
||||
|
@ -28,7 +53,7 @@ class Table {
|
|||
this._sort = tableInfo.sort
|
||||
}
|
||||
|
||||
async get({ primary, sort, otherProps }) {
|
||||
async get({ primary, sort, otherProps }: GetOpts) {
|
||||
let params = {
|
||||
TableName: this._name,
|
||||
Key: {
|
||||
|
@ -54,8 +79,8 @@ class Table {
|
|||
values,
|
||||
exists,
|
||||
otherProps,
|
||||
}) {
|
||||
let params = {
|
||||
}: UpdateOpts) {
|
||||
let params: any = {
|
||||
TableName: this._name,
|
||||
Key: {
|
||||
[this._primary]: primary,
|
||||
|
@ -83,7 +108,7 @@ class Table {
|
|||
return docClient.update(params).promise()
|
||||
}
|
||||
|
||||
async put({ item, otherProps }) {
|
||||
async put({ item, otherProps }: PutOpts) {
|
||||
if (
|
||||
item[this._primary] == null ||
|
||||
(this._sort && item[this._sort] == null)
|
||||
|
@ -101,9 +126,9 @@ class Table {
|
|||
}
|
||||
}
|
||||
|
||||
exports.init = endpoint => {
|
||||
export function init(endpoint: string) {
|
||||
let AWS = require("aws-sdk")
|
||||
let docClientParams = {
|
||||
let docClientParams: any = {
|
||||
correctClockSkew: true,
|
||||
region: AWS_REGION,
|
||||
}
|
||||
|
@ -115,13 +140,8 @@ exports.init = endpoint => {
|
|||
docClient = new AWS.DynamoDB.DocumentClient(docClientParams)
|
||||
}
|
||||
|
||||
exports.apiKeyTable = new Table(TableInfo.API_KEYS)
|
||||
exports.userTable = new Table(TableInfo.USERS)
|
||||
|
||||
if (env.isProd()) {
|
||||
exports.init(`https://dynamodb.${AWS_REGION}.amazonaws.com`)
|
||||
} else {
|
||||
if (!env.isProd()) {
|
||||
env._set("AWS_ACCESS_KEY_ID", "KEY_ID")
|
||||
env._set("AWS_SECRET_ACCESS_KEY", "SECRET_KEY")
|
||||
exports.init("http://localhost:8333")
|
||||
init("http://localhost:8333")
|
||||
}
|
|
@ -1,11 +1,17 @@
|
|||
const newid = require("./newid")
|
||||
import newid from "./newid"
|
||||
import { Row, View, Document } from "@budibase/types"
|
||||
|
||||
// bypass the main application db config
|
||||
// use in memory pouchdb directly
|
||||
const { db: dbCore } = require("@budibase/backend-core")
|
||||
import { db as dbCore } from "@budibase/backend-core"
|
||||
const Pouch = dbCore.getPouch({ inMemory: true })
|
||||
|
||||
exports.runView = async (view, calculation, group, data) => {
|
||||
export async function runView(
|
||||
view: View,
|
||||
calculation: boolean,
|
||||
group: string,
|
||||
data: Row[]
|
||||
) {
|
||||
// use a different ID each time for the DB, make sure they
|
||||
// are always unique for each query, don't want overlap
|
||||
// which could cause 409s
|
||||
|
@ -18,16 +24,16 @@ exports.runView = async (view, calculation, group, data) => {
|
|||
_rev: undefined,
|
||||
}))
|
||||
)
|
||||
let fn = (doc, emit) => emit(doc._id)
|
||||
eval("fn = " + view.map.replace("function (doc)", "function (doc, emit)"))
|
||||
const queryFns = {
|
||||
let fn = (doc: Document, emit: any) => emit(doc._id)
|
||||
eval("fn = " + view?.map?.replace("function (doc)", "function (doc, emit)"))
|
||||
const queryFns: any = {
|
||||
meta: view.meta,
|
||||
map: fn,
|
||||
}
|
||||
if (view.reduce) {
|
||||
queryFns.reduce = view.reduce
|
||||
}
|
||||
const response = await db.query(queryFns, {
|
||||
const response: { rows: Row[] } = await db.query(queryFns, {
|
||||
include_docs: !calculation,
|
||||
group: !!group,
|
||||
})
|
|
@ -1,16 +0,0 @@
|
|||
const core = require("@budibase/backend-core")
|
||||
const env = require("../environment")
|
||||
|
||||
exports.init = () => {
|
||||
const dbConfig = {
|
||||
replication: true,
|
||||
find: true,
|
||||
}
|
||||
|
||||
if (env.isTest() && !env.COUCH_DB_URL) {
|
||||
dbConfig.inMemory = true
|
||||
dbConfig.allDbs = true
|
||||
}
|
||||
|
||||
core.init({ db: dbConfig })
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { init as coreInit } from "@budibase/backend-core"
|
||||
import env = require("../environment")
|
||||
|
||||
export function init() {
|
||||
const dbConfig: any = {
|
||||
replication: true,
|
||||
find: true,
|
||||
}
|
||||
|
||||
if (env.isTest() && !env.COUCH_DB_URL) {
|
||||
dbConfig.inMemory = true
|
||||
dbConfig.allDbs = true
|
||||
}
|
||||
|
||||
coreInit({ db: dbConfig })
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
const { v4 } = require("uuid")
|
||||
|
||||
module.exports = function () {
|
||||
export = function (): string {
|
||||
return v4().replace(/-/g, "")
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
const { context } = require("@budibase/backend-core")
|
||||
const { DocumentType, SEPARATOR, ViewName, SearchIndexes } = require("../utils")
|
||||
import { context } from "@budibase/backend-core"
|
||||
import { DocumentType, SEPARATOR, ViewName, SearchIndexes } from "../utils"
|
||||
import { LinkDocument, Row } from "@budibase/types"
|
||||
const SCREEN_PREFIX = DocumentType.SCREEN + SEPARATOR
|
||||
|
||||
/**************************************************
|
||||
|
@ -19,16 +20,17 @@ const SCREEN_PREFIX = DocumentType.SCREEN + SEPARATOR
|
|||
* @returns {Promise<void>} The view now exists, please note that the next view of this query will actually build it,
|
||||
* so it may be slow.
|
||||
*/
|
||||
exports.createLinkView = async () => {
|
||||
export async function createLinkView() {
|
||||
const db = context.getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = {
|
||||
map: function (doc) {
|
||||
map: function (doc: LinkDocument) {
|
||||
// everything in this must remain constant as its going to Pouch, no external variables
|
||||
if (doc.type === "link") {
|
||||
let doc1 = doc.doc1
|
||||
let doc2 = doc.doc2
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
emit([doc1.tableId, doc1.rowId], {
|
||||
id: doc2.rowId,
|
||||
thisId: doc1.rowId,
|
||||
|
@ -37,6 +39,7 @@ exports.createLinkView = async () => {
|
|||
// if linking to same table can't emit twice
|
||||
if (doc1.tableId !== doc2.tableId) {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
emit([doc2.tableId, doc2.rowId], {
|
||||
id: doc1.rowId,
|
||||
thisId: doc2.rowId,
|
||||
|
@ -53,7 +56,7 @@ exports.createLinkView = async () => {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createRoutingView = async () => {
|
||||
export async function createRoutingView() {
|
||||
const db = context.getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
const view = {
|
||||
|
@ -74,7 +77,7 @@ exports.createRoutingView = async () => {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
async function searchIndex(indexName, fnString) {
|
||||
async function searchIndex(indexName: string, fnString: string) {
|
||||
const db = context.getAppDB()
|
||||
const designDoc = await db.get("_design/database")
|
||||
designDoc.indexes = {
|
||||
|
@ -86,11 +89,11 @@ async function searchIndex(indexName, fnString) {
|
|||
await db.put(designDoc)
|
||||
}
|
||||
|
||||
exports.createAllSearchIndex = async () => {
|
||||
export async function createAllSearchIndex() {
|
||||
await searchIndex(
|
||||
SearchIndexes.ROWS,
|
||||
function (doc) {
|
||||
function idx(input, prev) {
|
||||
function (doc: Row) {
|
||||
function idx(input: Row, prev?: string) {
|
||||
for (let key of Object.keys(input)) {
|
||||
let idxKey = prev != null ? `${prev}.${key}` : key
|
||||
idxKey = idxKey.replace(/ /g, "_")
|
||||
|
@ -98,6 +101,7 @@ exports.createAllSearchIndex = async () => {
|
|||
for (let val of input[key]) {
|
||||
if (typeof val !== "object") {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
index(idxKey, val, { store: true })
|
||||
}
|
||||
}
|
||||
|
@ -106,17 +110,20 @@ exports.createAllSearchIndex = async () => {
|
|||
}
|
||||
if (typeof input[key] === "string") {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
index(idxKey, input[key].toLowerCase(), { store: true })
|
||||
} else if (typeof input[key] !== "object") {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
index(idxKey, input[key], { store: true })
|
||||
} else {
|
||||
idx(input[key], idxKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (doc._id.startsWith("ro_")) {
|
||||
if (doc._id!.startsWith("ro_")) {
|
||||
// eslint-disable-next-line no-undef
|
||||
// @ts-ignore
|
||||
index("default", doc._id)
|
||||
idx(doc)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
const { rowEmission, tableEmission } = require("./utils")
|
||||
const mainEmitter = require("./index")
|
||||
const env = require("../environment")
|
||||
import { rowEmission, tableEmission } from "./utils"
|
||||
import mainEmitter from "./index"
|
||||
import env from "../environment"
|
||||
import { Table, Row } from "@budibase/types"
|
||||
|
||||
// max number of automations that can chain on top of each other
|
||||
// TODO: in future make this configurable at the automation level
|
||||
|
@ -13,14 +14,17 @@ const MAX_AUTOMATION_CHAIN = env.SELF_HOSTED ? 5 : 0
|
|||
* from getting stuck endlessly chaining.
|
||||
*/
|
||||
class AutomationEmitter {
|
||||
constructor(chainCount) {
|
||||
chainCount: number
|
||||
metadata: { automationChainCount: number }
|
||||
|
||||
constructor(chainCount: number) {
|
||||
this.chainCount = chainCount
|
||||
this.metadata = {
|
||||
automationChainCount: chainCount,
|
||||
}
|
||||
}
|
||||
|
||||
emitRow(eventName, appId, row, table = null) {
|
||||
emitRow(eventName: string, appId: string, row: Row, table?: Table) {
|
||||
// don't emit even if we've reached max automation chain
|
||||
if (this.chainCount >= MAX_AUTOMATION_CHAIN) {
|
||||
return
|
||||
|
@ -35,11 +39,12 @@ class AutomationEmitter {
|
|||
})
|
||||
}
|
||||
|
||||
emitTable(eventName, appId, table = null) {
|
||||
emitTable(eventName: string, appId: string, table?: Table) {
|
||||
// don't emit even if we've reached max automation chain
|
||||
if (this.chainCount > MAX_AUTOMATION_CHAIN) {
|
||||
return
|
||||
}
|
||||
|
||||
tableEmission({
|
||||
emitter: mainEmitter,
|
||||
eventName,
|
||||
|
@ -50,4 +55,4 @@ class AutomationEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = AutomationEmitter
|
||||
export = AutomationEmitter
|
|
@ -1,5 +1,6 @@
|
|||
const EventEmitter = require("events").EventEmitter
|
||||
const { rowEmission, tableEmission } = require("./utils")
|
||||
import { EventEmitter } from "events"
|
||||
import { rowEmission, tableEmission } from "./utils"
|
||||
import { Table, Row } from "@budibase/types"
|
||||
|
||||
/**
|
||||
* keeping event emitter in one central location as it might be used for things other than
|
||||
|
@ -12,19 +13,17 @@ const { rowEmission, tableEmission } = require("./utils")
|
|||
* This is specifically quite important for template strings used in automations.
|
||||
*/
|
||||
class BudibaseEmitter extends EventEmitter {
|
||||
emitRow(eventName, appId, row, table = null) {
|
||||
emitRow(eventName: string, appId: string, row: Row, table?: Table) {
|
||||
rowEmission({ emitter: this, eventName, appId, row, table })
|
||||
}
|
||||
|
||||
emitTable(eventName, appId, table = null) {
|
||||
emitTable(eventName: string, appId: string, table?: Table) {
|
||||
tableEmission({ emitter: this, eventName, appId, table })
|
||||
}
|
||||
|
||||
emitPort(portNumber) {
|
||||
emitPort(portNumber: number) {
|
||||
this.emit("internal:port", portNumber)
|
||||
}
|
||||
}
|
||||
|
||||
const emitter = new BudibaseEmitter()
|
||||
|
||||
module.exports = emitter
|
||||
export = BudibaseEmitter
|
|
@ -0,0 +1,5 @@
|
|||
import BudibaseEmitter from "./BudibaseEmitter"
|
||||
|
||||
const emitter = new BudibaseEmitter()
|
||||
|
||||
export = emitter
|
|
@ -1,38 +0,0 @@
|
|||
exports.rowEmission = ({ emitter, eventName, appId, row, table, metadata }) => {
|
||||
let event = {
|
||||
row,
|
||||
appId,
|
||||
tableId: row.tableId,
|
||||
}
|
||||
if (table) {
|
||||
event.table = table
|
||||
}
|
||||
event.id = row._id
|
||||
if (row._rev) {
|
||||
event.revision = row._rev
|
||||
}
|
||||
if (metadata) {
|
||||
event.metadata = metadata
|
||||
}
|
||||
emitter.emit(eventName, event)
|
||||
}
|
||||
|
||||
exports.tableEmission = ({ emitter, eventName, appId, table, metadata }) => {
|
||||
const tableId = table._id
|
||||
let event = {
|
||||
table: {
|
||||
...table,
|
||||
tableId: tableId,
|
||||
},
|
||||
appId,
|
||||
tableId: tableId,
|
||||
}
|
||||
event.id = tableId
|
||||
if (table._rev) {
|
||||
event.revision = table._rev
|
||||
}
|
||||
if (metadata) {
|
||||
event.metadata = metadata
|
||||
}
|
||||
emitter.emit(eventName, event)
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import { Table, Row } from "@budibase/types"
|
||||
import BudibaseEmitter from "./BudibaseEmitter"
|
||||
|
||||
type BBEventOpts = {
|
||||
emitter: BudibaseEmitter
|
||||
eventName: string
|
||||
appId: string
|
||||
table?: Table
|
||||
row?: Row
|
||||
metadata?: any
|
||||
}
|
||||
|
||||
interface BBEventTable extends Table {
|
||||
tableId?: string
|
||||
}
|
||||
|
||||
type BBEvent = {
|
||||
appId: string
|
||||
tableId?: string
|
||||
row?: Row
|
||||
table?: BBEventTable
|
||||
id?: string
|
||||
revision?: string
|
||||
metadata?: any
|
||||
}
|
||||
|
||||
export function rowEmission({
|
||||
emitter,
|
||||
eventName,
|
||||
appId,
|
||||
row,
|
||||
table,
|
||||
metadata,
|
||||
}: BBEventOpts) {
|
||||
let event: BBEvent = {
|
||||
row,
|
||||
appId,
|
||||
tableId: row?.tableId,
|
||||
}
|
||||
if (table) {
|
||||
event.table = table
|
||||
}
|
||||
event.id = row?._id
|
||||
if (row?._rev) {
|
||||
event.revision = row._rev
|
||||
}
|
||||
if (metadata) {
|
||||
event.metadata = metadata
|
||||
}
|
||||
emitter.emit(eventName, event)
|
||||
}
|
||||
|
||||
export function tableEmission({
|
||||
emitter,
|
||||
eventName,
|
||||
appId,
|
||||
table,
|
||||
metadata,
|
||||
}: BBEventOpts) {
|
||||
const tableId = table?._id
|
||||
const inputTable: BBEventTable | undefined = table
|
||||
if (inputTable) {
|
||||
inputTable.tableId = tableId
|
||||
}
|
||||
let event: BBEvent = {
|
||||
table: inputTable,
|
||||
appId,
|
||||
tableId: tableId,
|
||||
}
|
||||
event.id = tableId
|
||||
if (table?._rev) {
|
||||
event.revision = table._rev
|
||||
}
|
||||
if (metadata) {
|
||||
event.metadata = metadata
|
||||
}
|
||||
emitter.emit(eventName, event)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
const path = require("path")
|
||||
import path from "path"
|
||||
|
||||
// this simply runs all of our path join and resolve functions through
|
||||
// a central location incase we need to add some protection to file paths
|
||||
|
@ -8,7 +8,7 @@ const path = require("path")
|
|||
* @param args Any number of string arguments to add to a path
|
||||
* @returns {string} The final path ready to use
|
||||
*/
|
||||
exports.join = function (...args) {
|
||||
export function join(...args: any) {
|
||||
return path.join(...args)
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,6 @@ exports.join = function (...args) {
|
|||
* @param args Any number of string arguments to add to a path
|
||||
* @returns {string} The final path ready to use
|
||||
*/
|
||||
exports.resolve = function (...args) {
|
||||
export function resolve(...args: any) {
|
||||
return path.resolve(...args)
|
||||
}
|
|
@ -1,18 +1,25 @@
|
|||
const csv = require("csvtojson")
|
||||
const { FieldTypes } = require("../constants")
|
||||
import { FieldSchema, Table } from "@budibase/types"
|
||||
import csv from "csvtojson"
|
||||
import { FieldTypes } from "../constants"
|
||||
|
||||
type CsvParseOpts = {
|
||||
schema?: { [key: string]: any }
|
||||
existingTable: Table
|
||||
csvString?: string
|
||||
}
|
||||
|
||||
const VALIDATORS = {
|
||||
[FieldTypes.STRING]: () => true,
|
||||
[FieldTypes.OPTIONS]: () => true,
|
||||
[FieldTypes.BARCODEQR]: () => true,
|
||||
[FieldTypes.NUMBER]: attribute => {
|
||||
[FieldTypes.NUMBER]: (attribute?: string) => {
|
||||
// allow not to be present
|
||||
if (!attribute) {
|
||||
return true
|
||||
}
|
||||
return !isNaN(Number(attribute))
|
||||
},
|
||||
[FieldTypes.DATETIME]: attribute => {
|
||||
[FieldTypes.DATETIME]: (attribute?: string) => {
|
||||
// allow not to be present
|
||||
if (!attribute) {
|
||||
return true
|
||||
|
@ -22,13 +29,13 @@ const VALIDATORS = {
|
|||
}
|
||||
|
||||
const PARSERS = {
|
||||
[FieldTypes.NUMBER]: attribute => {
|
||||
[FieldTypes.NUMBER]: (attribute?: string) => {
|
||||
if (!attribute) {
|
||||
return attribute
|
||||
}
|
||||
return Number(attribute)
|
||||
},
|
||||
[FieldTypes.DATETIME]: attribute => {
|
||||
[FieldTypes.DATETIME]: (attribute?: string) => {
|
||||
if (!attribute) {
|
||||
return attribute
|
||||
}
|
||||
|
@ -36,10 +43,10 @@ const PARSERS = {
|
|||
},
|
||||
}
|
||||
|
||||
function parse(csvString, parsers) {
|
||||
export function parse(csvString: string, parsers: any) {
|
||||
const result = csv().fromString(csvString)
|
||||
|
||||
const schema = {}
|
||||
const schema: Record<string, any> = {}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
result.on("header", headers => {
|
||||
|
@ -77,16 +84,22 @@ function parse(csvString, parsers) {
|
|||
})
|
||||
}
|
||||
|
||||
function updateSchema({ schema, existingTable }) {
|
||||
export function updateSchema({
|
||||
schema,
|
||||
existingTable,
|
||||
}: {
|
||||
schema?: Record<string, any>
|
||||
existingTable: Table
|
||||
}) {
|
||||
if (!schema) {
|
||||
return schema
|
||||
}
|
||||
const finalSchema = {}
|
||||
const schemaKeyMap = {}
|
||||
const finalSchema: Record<string, FieldSchema> = {}
|
||||
const schemaKeyMap: Record<string, any> = {}
|
||||
Object.keys(schema).forEach(key => (schemaKeyMap[key.toLowerCase()] = key))
|
||||
for (let [key, field] of Object.entries(existingTable.schema)) {
|
||||
const lcKey = key.toLowerCase()
|
||||
const foundKey = schemaKeyMap[lcKey]
|
||||
const foundKey: string = schemaKeyMap[lcKey]
|
||||
if (foundKey) {
|
||||
finalSchema[key] = schema[foundKey]
|
||||
finalSchema[key].type = field.type
|
||||
|
@ -95,15 +108,22 @@ function updateSchema({ schema, existingTable }) {
|
|||
return finalSchema
|
||||
}
|
||||
|
||||
async function transform({ schema, csvString, existingTable }) {
|
||||
const colParser = {}
|
||||
export async function transform({
|
||||
schema,
|
||||
csvString,
|
||||
existingTable,
|
||||
}: CsvParseOpts) {
|
||||
if (!schema || !csvString) {
|
||||
throw new Error("Unable to transform CSV without schema")
|
||||
}
|
||||
const colParser: any = {}
|
||||
|
||||
// make sure the table has all the columns required for import
|
||||
if (existingTable) {
|
||||
schema = updateSchema({ schema, existingTable })
|
||||
}
|
||||
|
||||
for (let [key, field] of Object.entries(schema)) {
|
||||
for (let [key, field] of Object.entries(schema || {})) {
|
||||
// don't import data to auto columns
|
||||
if (!field.autocolumn) {
|
||||
colParser[key] = PARSERS[field.type] || field.type
|
||||
|
@ -112,8 +132,10 @@ async function transform({ schema, csvString, existingTable }) {
|
|||
|
||||
try {
|
||||
const data = await csv({ colParser }).fromString(csvString)
|
||||
const schemaKeyMap = {}
|
||||
Object.keys(schema).forEach(key => (schemaKeyMap[key.toLowerCase()] = key))
|
||||
const schemaKeyMap: any = {}
|
||||
Object.keys(schema || {}).forEach(
|
||||
key => (schemaKeyMap[key.toLowerCase()] = key)
|
||||
)
|
||||
for (let element of data) {
|
||||
if (!data) {
|
||||
continue
|
||||
|
@ -137,9 +159,3 @@ async function transform({ schema, csvString, existingTable }) {
|
|||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parse,
|
||||
transform,
|
||||
updateSchema,
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
const { join } = require("path")
|
||||
const { ObjectStoreBuckets } = require("../../constants")
|
||||
const fs = require("fs")
|
||||
const { objectStore } = require("@budibase/backend-core")
|
||||
const { resolve } = require("../centralPath")
|
||||
const env = require("../../environment")
|
||||
import { join } from "path"
|
||||
import { ObjectStoreBuckets } from "../../constants"
|
||||
import fs from "fs"
|
||||
import { objectStore } from "@budibase/backend-core"
|
||||
import { resolve } from "../centralPath"
|
||||
import env from "../../environment"
|
||||
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
|||
* @param appId The app ID to backup
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.backupClientLibrary = async appId => {
|
||||
export async function backupClientLibrary(appId: string) {
|
||||
// Copy existing manifest to tmp
|
||||
let tmpManifestPath
|
||||
try {
|
||||
|
@ -85,7 +85,7 @@ exports.backupClientLibrary = async appId => {
|
|||
* @param appId The app ID to update
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.updateClientLibrary = async appId => {
|
||||
export async function updateClientLibrary(appId: string) {
|
||||
let manifest, client
|
||||
|
||||
if (env.isDev()) {
|
||||
|
@ -124,7 +124,7 @@ exports.updateClientLibrary = async appId => {
|
|||
* @param appId The app ID to revert
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
exports.revertClientLibrary = async appId => {
|
||||
export async function revertClientLibrary(appId: string) {
|
||||
// Copy backups manifest to tmp directory
|
||||
const tmpManifestPath = await objectStore.retrieveToTmp(
|
||||
ObjectStoreBuckets.APPS,
|
|
@ -1,26 +1,17 @@
|
|||
const { budibaseTempDir } = require("../budibaseDir")
|
||||
const fs = require("fs")
|
||||
const { join } = require("path")
|
||||
import { budibaseTempDir } from "../budibaseDir"
|
||||
import fs from "fs"
|
||||
import { join } from "path"
|
||||
import { context, objectStore } from "@budibase/backend-core"
|
||||
import { ObjectStoreBuckets } from "../../constants"
|
||||
import { updateClientLibrary } from "./clientLibrary"
|
||||
import { checkSlashesInUrl } from "../"
|
||||
import env from "../../environment"
|
||||
import fetch from "node-fetch"
|
||||
const uuid = require("uuid/v4")
|
||||
const { context, objectStore } = require("@budibase/backend-core")
|
||||
const { ObjectStoreBuckets } = require("../../constants")
|
||||
const { updateClientLibrary } = require("./clientLibrary")
|
||||
const { checkSlashesInUrl } = require("../")
|
||||
const env = require("../../environment")
|
||||
const tar = require("tar")
|
||||
const fetch = require("node-fetch")
|
||||
const {
|
||||
upload,
|
||||
retrieve,
|
||||
retrieveToTmp,
|
||||
deleteFolder,
|
||||
downloadTarball,
|
||||
downloadTarballDirect,
|
||||
deleteFiles,
|
||||
} = objectStore
|
||||
|
||||
const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
||||
const NODE_MODULES_PATH = join(TOP_LEVEL_PATH, "node_modules")
|
||||
export const TOP_LEVEL_PATH = join(__dirname, "..", "..", "..")
|
||||
export const NODE_MODULES_PATH = join(TOP_LEVEL_PATH, "node_modules")
|
||||
const DATASOURCE_PATH = join(budibaseTempDir(), "datasource")
|
||||
|
||||
/**
|
||||
|
@ -34,14 +25,14 @@ const DATASOURCE_PATH = join(budibaseTempDir(), "datasource")
|
|||
/**
|
||||
* Upon first startup of instance there may not be everything we need in tmp directory, set it up.
|
||||
*/
|
||||
exports.init = () => {
|
||||
export function init() {
|
||||
const tempDir = budibaseTempDir()
|
||||
if (!fs.existsSync(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) {
|
||||
} catch (err: any) {
|
||||
if (!err || err.code !== "EEXIST") {
|
||||
throw err
|
||||
}
|
||||
|
@ -81,7 +72,7 @@ exports.checkDevelopmentEnvironment = () => {
|
|||
* @param {string} path The path to the handlebars file which is to be loaded.
|
||||
* @returns {string} The loaded handlebars file as a string - loaded as utf8.
|
||||
*/
|
||||
exports.loadHandlebarsFile = path => {
|
||||
export function loadHandlebarsFile(path: string) {
|
||||
return fs.readFileSync(path, "utf8")
|
||||
}
|
||||
|
||||
|
@ -91,13 +82,13 @@ exports.loadHandlebarsFile = path => {
|
|||
* @param {string} contents the contents of the file which is to be returned from the API.
|
||||
* @return {Object} the read stream which can be put into the koa context body.
|
||||
*/
|
||||
exports.apiFileReturn = contents => {
|
||||
export function apiFileReturn(contents: string) {
|
||||
const path = join(budibaseTempDir(), uuid())
|
||||
fs.writeFileSync(path, contents)
|
||||
return fs.createReadStream(path)
|
||||
}
|
||||
|
||||
exports.streamFile = path => {
|
||||
export function streamFile(path: string) {
|
||||
return fs.createReadStream(path)
|
||||
}
|
||||
|
||||
|
@ -106,7 +97,7 @@ exports.streamFile = path => {
|
|||
* @param {string} fileContents contents which will be written to a temp file.
|
||||
* @return {string} the path to the temp file.
|
||||
*/
|
||||
exports.storeTempFile = fileContents => {
|
||||
export function storeTempFile(fileContents: string) {
|
||||
const path = join(budibaseTempDir(), uuid())
|
||||
fs.writeFileSync(path, fileContents)
|
||||
return path
|
||||
|
@ -116,7 +107,7 @@ exports.storeTempFile = fileContents => {
|
|||
* Utility function for getting a file read stream - a simple in memory buffered read
|
||||
* stream doesn't work for pouchdb.
|
||||
*/
|
||||
exports.stringToFileStream = contents => {
|
||||
export function stringToFileStream(contents: string) {
|
||||
const path = exports.storeTempFile(contents)
|
||||
return fs.createReadStream(path)
|
||||
}
|
||||
|
@ -125,7 +116,7 @@ exports.stringToFileStream = contents => {
|
|||
* Creates a temp file and returns it from the API.
|
||||
* @param {string} fileContents the contents to be returned in file.
|
||||
*/
|
||||
exports.sendTempFile = fileContents => {
|
||||
export function sendTempFile(fileContents: string) {
|
||||
const path = exports.storeTempFile(fileContents)
|
||||
return fs.createReadStream(path)
|
||||
}
|
||||
|
@ -135,7 +126,7 @@ exports.sendTempFile = fileContents => {
|
|||
* @param {string} appId The ID of the app which is being created.
|
||||
* @return {Promise<void>} once promise completes app resources should be ready in object store.
|
||||
*/
|
||||
exports.createApp = async appId => {
|
||||
export async function createApp(appId: string) {
|
||||
await updateClientLibrary(appId)
|
||||
}
|
||||
|
||||
|
@ -144,8 +135,8 @@ exports.createApp = async appId => {
|
|||
* @param {string} appId The ID of the app which is being deleted.
|
||||
* @return {Promise<void>} once promise completes the app resources will be removed from object store.
|
||||
*/
|
||||
exports.deleteApp = async appId => {
|
||||
await deleteFolder(ObjectStoreBuckets.APPS, `${appId}/`)
|
||||
export async function deleteApp(appId: string) {
|
||||
await objectStore.deleteFolder(ObjectStoreBuckets.APPS, `${appId}/`)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,17 +145,21 @@ exports.deleteApp = async appId => {
|
|||
* @param name
|
||||
* @return {Promise<*>}
|
||||
*/
|
||||
exports.downloadTemplate = async (type, name) => {
|
||||
export async function downloadTemplate(type: string, name: string) {
|
||||
const DEFAULT_TEMPLATES_BUCKET =
|
||||
"prod-budi-templates.s3-eu-west-1.amazonaws.com"
|
||||
const templateUrl = `https://${DEFAULT_TEMPLATES_BUCKET}/templates/${type}/${name}.tar.gz`
|
||||
return downloadTarball(templateUrl, ObjectStoreBuckets.TEMPLATES, type)
|
||||
return objectStore.downloadTarball(
|
||||
templateUrl,
|
||||
ObjectStoreBuckets.TEMPLATES,
|
||||
type
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves component libraries from object store (or tmp symlink if in local)
|
||||
*/
|
||||
exports.getComponentLibraryManifest = async library => {
|
||||
export async function getComponentLibraryManifest(library: string) {
|
||||
const appId = context.getAppId()
|
||||
const filename = "manifest.json"
|
||||
/* istanbul ignore next */
|
||||
|
@ -182,12 +177,16 @@ exports.getComponentLibraryManifest = async library => {
|
|||
return require(path)
|
||||
}
|
||||
|
||||
if (!appId) {
|
||||
throw new Error("No app ID found - cannot get component libraries")
|
||||
}
|
||||
|
||||
let resp
|
||||
let path
|
||||
try {
|
||||
// Try to load the manifest from the new file location
|
||||
path = join(appId, filename)
|
||||
resp = await retrieve(ObjectStoreBuckets.APPS, path)
|
||||
resp = await objectStore.retrieve(ObjectStoreBuckets.APPS, path)
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`component-manifest-objectstore=failed appId=${appId} path=${path}`,
|
||||
|
@ -195,7 +194,7 @@ exports.getComponentLibraryManifest = async library => {
|
|||
)
|
||||
// Fallback to loading it from the old location for old apps
|
||||
path = join(appId, "node_modules", library, "package", filename)
|
||||
resp = await retrieve(ObjectStoreBuckets.APPS, path)
|
||||
resp = await objectStore.retrieve(ObjectStoreBuckets.APPS, path)
|
||||
}
|
||||
if (typeof resp !== "string") {
|
||||
resp = resp.toString("utf8")
|
||||
|
@ -207,14 +206,17 @@ exports.getComponentLibraryManifest = async library => {
|
|||
* All file reads come through here just to make sure all of them make sense
|
||||
* allows a centralised location to check logic is all good.
|
||||
*/
|
||||
exports.readFileSync = (filepath, options = "utf8") => {
|
||||
return fs.readFileSync(filepath, options)
|
||||
export function readFileSync(
|
||||
filepath: string,
|
||||
options: BufferEncoding = "utf8"
|
||||
) {
|
||||
return fs.readFileSync(filepath, { encoding: options })
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of app IDs makes sure file system is cleared of any of their temp info.
|
||||
*/
|
||||
exports.cleanup = appIds => {
|
||||
export function cleanup(appIds: string[]) {
|
||||
for (let appId of appIds) {
|
||||
const path = join(budibaseTempDir(), appId)
|
||||
if (fs.existsSync(path)) {
|
||||
|
@ -223,7 +225,7 @@ exports.cleanup = appIds => {
|
|||
}
|
||||
}
|
||||
|
||||
const createTempFolder = item => {
|
||||
export function createTempFolder(item: string) {
|
||||
const path = join(budibaseTempDir(), item)
|
||||
try {
|
||||
// remove old tmp directories automatically - don't combine
|
||||
|
@ -231,24 +233,22 @@ const createTempFolder = item => {
|
|||
fs.rmSync(path, { recursive: true, force: true })
|
||||
}
|
||||
fs.mkdirSync(path)
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
throw new Error(`Path cannot be created: ${err.message}`)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
exports.createTempFolder = createTempFolder
|
||||
|
||||
const extractTarball = async (fromFilePath, toPath) => {
|
||||
export async function extractTarball(fromFilePath: string, toPath: string) {
|
||||
await tar.extract({
|
||||
file: fromFilePath,
|
||||
C: toPath,
|
||||
})
|
||||
}
|
||||
exports.extractTarball = extractTarball
|
||||
|
||||
const getPluginMetadata = async path => {
|
||||
let metadata = {}
|
||||
export async function getPluginMetadata(path: string) {
|
||||
let metadata: { schema?: any; package?: any } = {}
|
||||
try {
|
||||
const pkg = fs.readFileSync(join(path, "package.json"), "utf8")
|
||||
const schema = fs.readFileSync(join(path, "schema.json"), "utf8")
|
||||
|
@ -265,7 +265,7 @@ const getPluginMetadata = async path => {
|
|||
"package.json is missing one of 'name', 'version' or 'description'."
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
throw new Error(
|
||||
`Unable to process schema.json/package.json in plugin. ${err.message}`
|
||||
)
|
||||
|
@ -273,9 +273,12 @@ const getPluginMetadata = async path => {
|
|||
|
||||
return { metadata, directory: path }
|
||||
}
|
||||
exports.getPluginMetadata = getPluginMetadata
|
||||
|
||||
exports.getDatasourcePlugin = async (name, url, hash) => {
|
||||
export async function getDatasourcePlugin(
|
||||
name: string,
|
||||
url: string,
|
||||
hash: string
|
||||
) {
|
||||
if (!fs.existsSync(DATASOURCE_PATH)) {
|
||||
fs.mkdirSync(DATASOURCE_PATH)
|
||||
}
|
||||
|
@ -311,7 +314,7 @@ exports.getDatasourcePlugin = async (name, url, hash) => {
|
|||
/**
|
||||
* Find for a file recursively from start path applying filter, return first match
|
||||
*/
|
||||
exports.findFileRec = (startPath, filter) => {
|
||||
export function findFileRec(startPath: string, filter: any) {
|
||||
if (!fs.existsSync(startPath)) {
|
||||
return
|
||||
}
|
||||
|
@ -332,21 +335,10 @@ exports.findFileRec = (startPath, filter) => {
|
|||
/**
|
||||
* Remove a folder which is not empty from the file system
|
||||
*/
|
||||
exports.deleteFolderFileSystem = path => {
|
||||
export function deleteFolderFileSystem(path: string) {
|
||||
if (!fs.existsSync(path)) {
|
||||
return
|
||||
}
|
||||
|
||||
fs.rmSync(path, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Full function definition for below can be found in the utilities.
|
||||
*/
|
||||
exports.upload = upload
|
||||
exports.retrieve = retrieve
|
||||
exports.retrieveToTmp = retrieveToTmp
|
||||
exports.deleteFiles = deleteFiles
|
||||
exports.downloadTarballDirect = downloadTarballDirect
|
||||
exports.TOP_LEVEL_PATH = TOP_LEVEL_PATH
|
||||
exports.NODE_MODULES_PATH = NODE_MODULES_PATH
|
|
@ -1,21 +1,19 @@
|
|||
const jimp = require("jimp")
|
||||
import jimp from "jimp"
|
||||
|
||||
const FORMATS = {
|
||||
IMAGES: ["png", "jpg", "jpeg", "gif", "bmp", "tiff"],
|
||||
}
|
||||
|
||||
function processImage(file) {
|
||||
function processImage(file: { path: string }) {
|
||||
// this will overwrite the temp file
|
||||
return jimp.read(file.path).then(img => {
|
||||
return img.resize(300, jimp.AUTO).write(file.path)
|
||||
})
|
||||
}
|
||||
|
||||
async function process(file) {
|
||||
export async function process(file: { extension: string; path: string }) {
|
||||
if (FORMATS.IMAGES.includes(file.extension.toLowerCase())) {
|
||||
await processImage(file)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
exports.process = process
|
|
@ -1,8 +1,9 @@
|
|||
const env = require("../environment")
|
||||
const { plugins: ProPlugins } = require("@budibase/pro")
|
||||
const { objectStore } = require("@budibase/backend-core")
|
||||
import env from "../environment"
|
||||
import { plugins as ProPlugins } from "@budibase/pro"
|
||||
import { objectStore } from "@budibase/backend-core"
|
||||
import { Plugin } from "@budibase/types"
|
||||
|
||||
exports.enrichPluginURLs = plugins => {
|
||||
export function enrichPluginURLs(plugins: Plugin[]) {
|
||||
if (!plugins || !plugins.length) {
|
||||
return []
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
let events = require("events")
|
||||
|
||||
/**
|
||||
* Bull works with a Job wrapper around all messages that contains a lot more information about
|
||||
* the state of the message, this object constructor implements the same schema of Bull jobs
|
||||
* for the sake of maintaining API consistency.
|
||||
* @param {string} queue The name of the queue which the message will be carried on.
|
||||
* @param {object} message The JSON message which will be passed back to the consumer.
|
||||
* @returns {Object} A new job which can now be put onto the queue, this is mostly an
|
||||
* internal structure so that an in memory queue can be easily swapped for a Bull queue.
|
||||
*/
|
||||
function newJob(queue, message) {
|
||||
return {
|
||||
timestamp: Date.now(),
|
||||
queue: queue,
|
||||
data: message,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is designed to replicate Bull (https://github.com/OptimalBits/bull) in memory as a sort of mock.
|
||||
* It is relatively simple, using an event emitter internally to register when messages are available
|
||||
* to the consumers - in can support many inputs and many consumers.
|
||||
*/
|
||||
class InMemoryQueue {
|
||||
/**
|
||||
* The constructor the queue, exactly the same as that of Bulls.
|
||||
* @param {string} name The name of the queue which is being configured.
|
||||
* @param {object|null} opts This is not used by the in memory queue as there is no real use
|
||||
* case when in memory, but is the same API as Bull
|
||||
*/
|
||||
constructor(name, opts = null) {
|
||||
this._name = name
|
||||
this._opts = opts
|
||||
this._messages = []
|
||||
this._emitter = new events.EventEmitter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Same callback API as Bull, each callback passed to this will consume messages as they are
|
||||
* available. Please note this is a queue service, not a notification service, so each
|
||||
* consumer will receive different messages.
|
||||
* @param {function<object>} func The callback function which will return a "Job", the same
|
||||
* as the Bull API, within this job the property "data" contains the JSON message. Please
|
||||
* note this is incredibly limited compared to Bull as in reality the Job would contain
|
||||
* a lot more information about the queue and current status of Bull cluster.
|
||||
*/
|
||||
process(func) {
|
||||
this._emitter.on("message", async () => {
|
||||
if (this._messages.length <= 0) {
|
||||
return
|
||||
}
|
||||
let msg = this._messages.shift()
|
||||
let resp = func(msg)
|
||||
if (resp.then != null) {
|
||||
await resp
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// simply puts a message to the queue and emits to the queue for processing
|
||||
/**
|
||||
* Simple function to replicate the add message functionality of Bull, putting
|
||||
* a new message on the queue. This then emits an event which will be used to
|
||||
* return the message to a consumer (if one is attached).
|
||||
* @param {object} msg A message to be transported over the queue, this should be
|
||||
* a JSON message as this is required by Bull.
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
add(msg, repeat) {
|
||||
if (typeof msg !== "object") {
|
||||
throw "Queue only supports carrying JSON."
|
||||
}
|
||||
this._messages.push(newJob(this._name, msg))
|
||||
this._emitter.emit("message")
|
||||
}
|
||||
|
||||
/**
|
||||
* replicating the close function from bull, which waits for jobs to finish.
|
||||
*/
|
||||
async close() {
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes a cron which has been implemented, this is part of Bull API.
|
||||
* @param {string} cronJobId The cron which is to be removed.
|
||||
*/
|
||||
removeRepeatableByKey(cronJobId) {
|
||||
// TODO: implement for testing
|
||||
console.log(cronJobId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented for tests
|
||||
*/
|
||||
getRepeatableJobs() {
|
||||
return []
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
removeJobs(pattern) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented for tests
|
||||
*/
|
||||
async clean() {
|
||||
return []
|
||||
}
|
||||
|
||||
async getJob() {
|
||||
return {}
|
||||
}
|
||||
|
||||
on() {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InMemoryQueue
|
|
@ -1,4 +1,5 @@
|
|||
const { FieldTypes } = require("../../constants")
|
||||
// @ts-nocheck
|
||||
import { FieldTypes } from "../../constants"
|
||||
|
||||
/**
|
||||
* A map of how we convert various properties in rows to each other based on the row type.
|
|
@ -1,9 +1,13 @@
|
|||
const fetch = require("node-fetch")
|
||||
const { VM, VMScript } = require("vm2")
|
||||
import fetch from "node-fetch"
|
||||
import { VM, VMScript } from "vm2"
|
||||
const JS_TIMEOUT_MS = 1000
|
||||
|
||||
class ScriptRunner {
|
||||
constructor(script, context) {
|
||||
vm: VM
|
||||
results: { out: string }
|
||||
script: VMScript
|
||||
|
||||
constructor(script: string, context: any) {
|
||||
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
|
||||
this.vm = new VM({
|
||||
timeout: JS_TIMEOUT_MS,
|
||||
|
@ -21,4 +25,4 @@ class ScriptRunner {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = ScriptRunner
|
||||
export = ScriptRunner
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
export = {
|
||||
OK: 200,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDDEN: 403,
|
|
@ -7,7 +7,7 @@ function getNewQuotaReset() {
|
|||
return Date.now() + 2592000000
|
||||
}
|
||||
|
||||
function resetQuotasIfRequired(quota) {
|
||||
function resetQuotasIfRequired(quota: { quotaReset: number; usageQuota: any }) {
|
||||
// Check if the quota needs reset
|
||||
if (Date.now() >= quota.quotaReset) {
|
||||
quota.quotaReset = getNewQuotaReset()
|
|
@ -12,3 +12,4 @@ export * from "./row"
|
|||
export * from "./user"
|
||||
export * from "./backup"
|
||||
export * from "./webhook"
|
||||
export * from "./links"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export interface LinkDocument {
|
||||
type: string
|
||||
doc1: {
|
||||
rowId: string
|
||||
fieldName: string
|
||||
tableId: string
|
||||
}
|
||||
doc2: {
|
||||
rowId: string
|
||||
fieldName: string
|
||||
tableId: string
|
||||
}
|
||||
}
|
|
@ -8,10 +8,12 @@ export interface FieldSchema {
|
|||
externalType?: string
|
||||
fieldName?: string
|
||||
name: string
|
||||
sortable?: boolean
|
||||
tableId?: string
|
||||
relationshipType?: string
|
||||
through?: string
|
||||
foreignKey?: string
|
||||
icon?: string
|
||||
autocolumn?: boolean
|
||||
subtype?: string
|
||||
throughFrom?: string
|
||||
|
@ -22,6 +24,7 @@ export interface FieldSchema {
|
|||
ignoreTimezones?: boolean
|
||||
timeOnly?: boolean
|
||||
lastID?: number
|
||||
useRichText?: boolean | null
|
||||
meta?: {
|
||||
toTable: string
|
||||
toKey: string
|
||||
|
@ -31,10 +34,22 @@ export interface FieldSchema {
|
|||
email?: boolean
|
||||
inclusion?: string[]
|
||||
length?: {
|
||||
minimum?: string | number
|
||||
maximum?: string | number
|
||||
minimum?: string | number | null
|
||||
maximum?: string | number | null
|
||||
}
|
||||
numericality?: {
|
||||
greaterThanOrEqualTo: string | null
|
||||
lessThanOrEqualTo: string | null
|
||||
}
|
||||
presence?:
|
||||
| boolean
|
||||
| {
|
||||
allowEmpty?: boolean
|
||||
}
|
||||
datetime?: {
|
||||
latest: string
|
||||
earliest: string
|
||||
}
|
||||
presence?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ export interface View {
|
|||
filters: ViewFilter[]
|
||||
schema: ViewSchema
|
||||
calculation?: ViewCalculation
|
||||
map?: string
|
||||
reduce?: any
|
||||
meta?: Record<string, any>
|
||||
}
|
||||
|
||||
export type ViewSchema = ViewCountOrSumSchema | ViewStatisticsSchema
|
||||
|
|
Loading…
Reference in New Issue