Build and test fixes
This commit is contained in:
parent
8b4f4c813a
commit
3b9142f103
|
@ -2,7 +2,7 @@
|
|||
"name": "@budibase/backend-core",
|
||||
"version": "1.0.126-alpha.0",
|
||||
"description": "Budibase backend core libraries used in server and worker",
|
||||
"main": "src/index.js",
|
||||
"main": "src/index.ts",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
|
@ -36,22 +36,29 @@
|
|||
"zlib": "^1.0.5"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "ts-jest",
|
||||
"testEnvironment": "node",
|
||||
"setupFiles": [
|
||||
"./scripts/jestSetup.js"
|
||||
"./scripts/jestSetup.ts"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@shopify/jest-koa-mocks": "^3.1.5",
|
||||
"@budibase/types": "^1.0.126-alpha.0",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/koa": "^2.13.3",
|
||||
"@types/node": "^15.12.4",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@budibase/types": "^1.0.126-alpha.0",
|
||||
"typescript": "^4.5.5",
|
||||
"@shopify/jest-koa-mocks": "^3.1.5",
|
||||
"@types/tar-fs": "^2.0.1",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"ioredis-mock": "^5.5.5",
|
||||
"jest": "^26.6.3",
|
||||
"jest": "^27.0.3",
|
||||
"koa": "2.7.0",
|
||||
"pouchdb-adapter-memory": "^7.2.2",
|
||||
"pouchdb-all-dbs": "^1.0.2",
|
||||
"timekeeper": "^2.2.0"
|
||||
"timekeeper": "^2.2.0",
|
||||
"ts-jest": "^27.0.3",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc"
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const env = require("../src/environment")
|
||||
const { mocks } = require("../testUtils")
|
||||
import env from "../src/environment"
|
||||
import { mocks } from "../testUtils"
|
||||
|
||||
// mock all dates to 2020-01-01T00:00:00.000Z
|
||||
// use tk.reset() to use real dates in individual tests
|
||||
const tk = require("timekeeper")
|
||||
import tk from "timekeeper"
|
||||
tk.freeze(mocks.date.MOCK_DATE)
|
||||
|
||||
env._set("SELF_HOSTED", "1")
|
|
@ -1,6 +1,6 @@
|
|||
import { newid } from "../hashing"
|
||||
import { DEFAULT_TENANT_ID, Configs } from "../constants"
|
||||
import * as env from "../environment"
|
||||
import env from "../environment"
|
||||
import { SEPARATOR, DocumentTypes } from "./constants"
|
||||
import { getTenantId, getGlobalDBName } from "../tenancy"
|
||||
import fetch from "node-fetch"
|
||||
|
|
|
@ -6,7 +6,7 @@ function isTest() {
|
|||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export = {
|
||||
JWT_SECRET: process.env.JWT_SECRET,
|
||||
COUCH_DB_URL: process.env.COUCH_DB_URL,
|
||||
COUCH_DB_USERNAME: process.env.COUCH_DB_USER,
|
||||
|
@ -26,7 +26,7 @@ module.exports = {
|
|||
process.env.ACCOUNT_PORTAL_URL || "https://account.budibase.app",
|
||||
ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY,
|
||||
DISABLE_ACCOUNT_PORTAL: process.env.DISABLE_ACCOUNT_PORTAL,
|
||||
SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED),
|
||||
SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED || ""),
|
||||
COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
|
||||
PLATFORM_URL: process.env.PLATFORM_URL,
|
||||
POSTHOG_TOKEN: process.env.POSTHOG_TOKEN,
|
||||
|
@ -34,7 +34,7 @@ module.exports = {
|
|||
TENANT_FEATURE_FLAGS: process.env.TENANT_FEATURE_FLAGS,
|
||||
USE_COUCH: process.env.USE_COUCH || true,
|
||||
isTest,
|
||||
_set(key, value) {
|
||||
_set(key: any, value: any) {
|
||||
process.env[key] = value
|
||||
module.exports[key] = value
|
||||
},
|
|
@ -1,10 +1,10 @@
|
|||
import { AppServedEvent } from "./../../../../types/src/events/serve"
|
||||
import { processEvent } from "../events"
|
||||
import {
|
||||
App,
|
||||
BuilderServedEvent,
|
||||
Events,
|
||||
AppPreviewServedEvent,
|
||||
AppServedEvent,
|
||||
} from "@budibase/types"
|
||||
|
||||
/* eslint-disable */
|
||||
|
|
|
@ -11,6 +11,9 @@ import {
|
|||
ViewFilterDeletedEvent,
|
||||
ViewFilterUpdatedEvent,
|
||||
ViewUpdatedEvent,
|
||||
View,
|
||||
Table,
|
||||
TableExportFormat,
|
||||
} from "@budibase/types"
|
||||
|
||||
/* eslint-disable */
|
||||
|
@ -30,7 +33,7 @@ export function deleted() {
|
|||
processEvent(Events.VIEW_DELETED, properties)
|
||||
}
|
||||
|
||||
export function exported(table, format) {
|
||||
export function exported(table: Table, format: TableExportFormat) {
|
||||
const properties: ViewExportedEvent = {}
|
||||
processEvent(Events.VIEW_EXPORTED, properties)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const db = require("./db")
|
||||
const errors = require("./errors")
|
||||
import db from "./db"
|
||||
import errors from "./errors"
|
||||
import * as events from "./events"
|
||||
|
||||
module.exports = {
|
||||
init(opts = {}) {
|
||||
export = {
|
||||
init(opts: any = {}) {
|
||||
db.init(opts.db)
|
||||
},
|
||||
// some default exports from the library, however these ideally shouldn't
|
||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||
auth: require("../auth"),
|
||||
constants: require("../constants"),
|
||||
migrations: require("../migrations"),
|
||||
errors: require("./errors"),
|
||||
errors,
|
||||
...errors.errors,
|
||||
env: require("./environment"),
|
||||
accounts: require("./cloud/accounts"),
|
|
@ -1,9 +1,9 @@
|
|||
import sanitize from "sanitize-s3-objectkey"
|
||||
const sanitize = require("sanitize-s3-objectkey")
|
||||
import AWS from "aws-sdk"
|
||||
import stream from "stream"
|
||||
import fetch from "node-fetch"
|
||||
import tar from "tar-fs"
|
||||
import zlib from "zlib"
|
||||
const zlib = require("zlib")
|
||||
import { promisify } from "util"
|
||||
import { join } from "path"
|
||||
import fs from "fs"
|
||||
|
@ -18,7 +18,7 @@ const STATE = {
|
|||
bucketCreationPromises: {},
|
||||
}
|
||||
|
||||
const CONTENT_TYPE_MAP = {
|
||||
const CONTENT_TYPE_MAP: any = {
|
||||
html: "text/html",
|
||||
css: "text/css",
|
||||
js: "application/javascript",
|
||||
|
@ -32,20 +32,16 @@ const STRING_CONTENT_TYPES = [
|
|||
]
|
||||
|
||||
// does normal sanitization and then swaps dev apps to apps
|
||||
function sanitizeKey(input) {
|
||||
export function sanitizeKey(input: any) {
|
||||
return sanitize(sanitizeBucket(input)).replace(/\\/g, "/")
|
||||
}
|
||||
|
||||
exports.sanitizeKey = sanitizeKey
|
||||
|
||||
// simply handles the dev app to app conversion
|
||||
function sanitizeBucket(input) {
|
||||
export function sanitizeBucket(input: any) {
|
||||
return input.replace(new RegExp(APP_DEV_PREFIX, "g"), APP_PREFIX)
|
||||
}
|
||||
|
||||
exports.sanitizeBucket = sanitizeBucket
|
||||
|
||||
function publicPolicy(bucketName) {
|
||||
function publicPolicy(bucketName: any) {
|
||||
return {
|
||||
Version: "2012-10-17",
|
||||
Statement: [
|
||||
|
@ -69,13 +65,13 @@ const PUBLIC_BUCKETS = [ObjectStoreBuckets.APPS, ObjectStoreBuckets.GLOBAL]
|
|||
* @return {Object} an S3 object store object, check S3 Nodejs SDK for usage.
|
||||
* @constructor
|
||||
*/
|
||||
exports.ObjectStore = bucket => {
|
||||
export const ObjectStore = (bucket: any) => {
|
||||
AWS.config.update({
|
||||
accessKeyId: env.MINIO_ACCESS_KEY,
|
||||
secretAccessKey: env.MINIO_SECRET_KEY,
|
||||
region: env.AWS_REGION,
|
||||
})
|
||||
const config = {
|
||||
const config: any = {
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: "v4",
|
||||
apiVersion: "2006-03-01",
|
||||
|
@ -93,7 +89,7 @@ exports.ObjectStore = bucket => {
|
|||
* Given an object store and a bucket name this will make sure the bucket exists,
|
||||
* if it does not exist then it will create it.
|
||||
*/
|
||||
exports.makeSureBucketExists = async (client, bucketName) => {
|
||||
export const makeSureBucketExists = async (client: any, bucketName: any) => {
|
||||
bucketName = sanitizeBucket(bucketName)
|
||||
try {
|
||||
await client
|
||||
|
@ -101,8 +97,8 @@ exports.makeSureBucketExists = async (client, bucketName) => {
|
|||
Bucket: bucketName,
|
||||
})
|
||||
.promise()
|
||||
} catch (err) {
|
||||
const promises = STATE.bucketCreationPromises
|
||||
} catch (err: any) {
|
||||
const promises: any = STATE.bucketCreationPromises
|
||||
const doesntExist = err.statusCode === 404,
|
||||
noAccess = err.statusCode === 403
|
||||
if (promises[bucketName]) {
|
||||
|
@ -138,20 +134,20 @@ exports.makeSureBucketExists = async (client, bucketName) => {
|
|||
* Uploads the contents of a file given the required parameters, useful when
|
||||
* temp files in use (for example file uploaded as an attachment).
|
||||
*/
|
||||
exports.upload = async ({
|
||||
export const upload = async ({
|
||||
bucket: bucketName,
|
||||
filename,
|
||||
path,
|
||||
type,
|
||||
metadata,
|
||||
}) => {
|
||||
}: any) => {
|
||||
const extension = [...filename.split(".")].pop()
|
||||
const fileBytes = fs.readFileSync(path)
|
||||
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||
const objectStore = ObjectStore(bucketName)
|
||||
await makeSureBucketExists(objectStore, bucketName)
|
||||
|
||||
const config = {
|
||||
const config: any = {
|
||||
// windows file paths need to be converted to forward slashes for s3
|
||||
Key: sanitizeKey(filename),
|
||||
Body: fileBytes,
|
||||
|
@ -167,9 +163,14 @@ exports.upload = async ({
|
|||
* Similar to the upload function but can be used to send a file stream
|
||||
* through to the object store.
|
||||
*/
|
||||
exports.streamUpload = async (bucketName, filename, stream, extra = {}) => {
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||
export const streamUpload = async (
|
||||
bucketName: any,
|
||||
filename: any,
|
||||
stream: any,
|
||||
extra = {}
|
||||
) => {
|
||||
const objectStore = ObjectStore(bucketName)
|
||||
await makeSureBucketExists(objectStore, bucketName)
|
||||
|
||||
const params = {
|
||||
Bucket: sanitizeBucket(bucketName),
|
||||
|
@ -184,13 +185,13 @@ exports.streamUpload = async (bucketName, filename, stream, extra = {}) => {
|
|||
* retrieves the contents of a file from the object store, if it is a known content type it
|
||||
* will be converted, otherwise it will be returned as a buffer stream.
|
||||
*/
|
||||
exports.retrieve = async (bucketName, filepath) => {
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
export const retrieve = async (bucketName: any, filepath: any) => {
|
||||
const objectStore = ObjectStore(bucketName)
|
||||
const params = {
|
||||
Bucket: sanitizeBucket(bucketName),
|
||||
Key: sanitizeKey(filepath),
|
||||
}
|
||||
const response = await objectStore.getObject(params).promise()
|
||||
const response: any = await objectStore.getObject(params).promise()
|
||||
// currently these are all strings
|
||||
if (STRING_CONTENT_TYPES.includes(response.ContentType)) {
|
||||
return response.Body.toString("utf8")
|
||||
|
@ -202,10 +203,10 @@ exports.retrieve = async (bucketName, filepath) => {
|
|||
/**
|
||||
* Same as retrieval function but puts to a temporary file.
|
||||
*/
|
||||
exports.retrieveToTmp = async (bucketName, filepath) => {
|
||||
export const retrieveToTmp = async (bucketName: any, filepath: any) => {
|
||||
bucketName = sanitizeBucket(bucketName)
|
||||
filepath = sanitizeKey(filepath)
|
||||
const data = await exports.retrieve(bucketName, filepath)
|
||||
const data = await retrieve(bucketName, filepath)
|
||||
const outputPath = join(budibaseTempDir(), v4())
|
||||
fs.writeFileSync(outputPath, data)
|
||||
return outputPath
|
||||
|
@ -214,9 +215,9 @@ exports.retrieveToTmp = async (bucketName, filepath) => {
|
|||
/**
|
||||
* Delete a single file.
|
||||
*/
|
||||
exports.deleteFile = async (bucketName, filepath) => {
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||
export const deleteFile = async (bucketName: any, filepath: any) => {
|
||||
const objectStore = ObjectStore(bucketName)
|
||||
await makeSureBucketExists(objectStore, bucketName)
|
||||
const params = {
|
||||
Bucket: bucketName,
|
||||
Key: filepath,
|
||||
|
@ -224,13 +225,13 @@ exports.deleteFile = async (bucketName, filepath) => {
|
|||
return objectStore.deleteObject(params)
|
||||
}
|
||||
|
||||
exports.deleteFiles = async (bucketName, filepaths) => {
|
||||
const objectStore = exports.ObjectStore(bucketName)
|
||||
await exports.makeSureBucketExists(objectStore, bucketName)
|
||||
export const deleteFiles = async (bucketName: any, filepaths: any) => {
|
||||
const objectStore = ObjectStore(bucketName)
|
||||
await makeSureBucketExists(objectStore, bucketName)
|
||||
const params = {
|
||||
Bucket: bucketName,
|
||||
Delete: {
|
||||
Objects: filepaths.map(path => ({ Key: path })),
|
||||
Objects: filepaths.map((path: any) => ({ Key: path })),
|
||||
},
|
||||
}
|
||||
return objectStore.deleteObjects(params).promise()
|
||||
|
@ -239,38 +240,45 @@ exports.deleteFiles = async (bucketName, filepaths) => {
|
|||
/**
|
||||
* Delete a path, including everything within.
|
||||
*/
|
||||
exports.deleteFolder = async (bucketName, folder) => {
|
||||
export const deleteFolder = async (
|
||||
bucketName: any,
|
||||
folder: any
|
||||
): Promise<any> => {
|
||||
bucketName = sanitizeBucket(bucketName)
|
||||
folder = sanitizeKey(folder)
|
||||
const client = exports.ObjectStore(bucketName)
|
||||
const client = ObjectStore(bucketName)
|
||||
const listParams = {
|
||||
Bucket: bucketName,
|
||||
Prefix: folder,
|
||||
}
|
||||
|
||||
let response = await client.listObjects(listParams).promise()
|
||||
let response: any = await client.listObjects(listParams).promise()
|
||||
if (response.Contents.length === 0) {
|
||||
return
|
||||
}
|
||||
const deleteParams = {
|
||||
const deleteParams: any = {
|
||||
Bucket: bucketName,
|
||||
Delete: {
|
||||
Objects: [],
|
||||
},
|
||||
}
|
||||
|
||||
response.Contents.forEach(content => {
|
||||
response.Contents.forEach((content: any) => {
|
||||
deleteParams.Delete.Objects.push({ Key: content.Key })
|
||||
})
|
||||
|
||||
response = await client.deleteObjects(deleteParams).promise()
|
||||
// can only empty 1000 items at once
|
||||
if (response.Deleted.length === 1000) {
|
||||
return exports.deleteFolder(bucketName, folder)
|
||||
return deleteFolder(bucketName, folder)
|
||||
}
|
||||
}
|
||||
|
||||
exports.uploadDirectory = async (bucketName, localPath, bucketPath) => {
|
||||
export const uploadDirectory = async (
|
||||
bucketName: any,
|
||||
localPath: any,
|
||||
bucketPath: any
|
||||
) => {
|
||||
bucketName = sanitizeBucket(bucketName)
|
||||
let uploads = []
|
||||
const files = fs.readdirSync(localPath, { withFileTypes: true })
|
||||
|
@ -278,17 +286,15 @@ exports.uploadDirectory = async (bucketName, localPath, bucketPath) => {
|
|||
const path = sanitizeKey(join(bucketPath, file.name))
|
||||
const local = join(localPath, file.name)
|
||||
if (file.isDirectory()) {
|
||||
uploads.push(exports.uploadDirectory(bucketName, local, path))
|
||||
uploads.push(uploadDirectory(bucketName, local, path))
|
||||
} else {
|
||||
uploads.push(
|
||||
exports.streamUpload(bucketName, path, fs.createReadStream(local))
|
||||
)
|
||||
uploads.push(streamUpload(bucketName, path, fs.createReadStream(local)))
|
||||
}
|
||||
}
|
||||
await Promise.all(uploads)
|
||||
}
|
||||
|
||||
exports.downloadTarball = async (url, bucketName, path) => {
|
||||
export const downloadTarball = async (url: any, bucketName: any, path: any) => {
|
||||
bucketName = sanitizeBucket(bucketName)
|
||||
path = sanitizeKey(path)
|
||||
const response = await fetch(url)
|
||||
|
@ -299,7 +305,7 @@ exports.downloadTarball = async (url, bucketName, path) => {
|
|||
const tmpPath = join(budibaseTempDir(), path)
|
||||
await streamPipeline(response.body, zlib.Unzip(), tar.extract(tmpPath))
|
||||
if (!env.isTest() && env.SELF_HOSTED) {
|
||||
await exports.uploadDirectory(bucketName, tmpPath, path)
|
||||
await uploadDirectory(bucketName, tmpPath, path)
|
||||
}
|
||||
// return the temporary path incase there is a use for it
|
||||
return tmpPath
|
|
@ -1,7 +0,0 @@
|
|||
const mocks = require("./mocks")
|
||||
const structures = require("./structures")
|
||||
|
||||
module.exports = {
|
||||
mocks,
|
||||
structures,
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export * as mocks from "./mocks"
|
||||
export * as structures from "./structures"
|
|
@ -59,7 +59,7 @@ jest.mock("../../../events", () => {
|
|||
created: jest.fn(),
|
||||
updated: jest.fn(),
|
||||
deleted: jest.fn(),
|
||||
import: jest.fn(),
|
||||
imported: jest.fn(),
|
||||
previewed: jest.fn(),
|
||||
},
|
||||
role: {
|
||||
|
@ -70,7 +70,7 @@ jest.mock("../../../events", () => {
|
|||
unassigned: jest.fn(),
|
||||
},
|
||||
row: {
|
||||
import: jest.fn(),
|
||||
imported: jest.fn(),
|
||||
},
|
||||
screen: {
|
||||
created: jest.fn(),
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
require("../mocks")
|
||||
const koa = require("./koa")
|
||||
|
||||
const structures = {
|
||||
koa,
|
||||
}
|
||||
|
||||
module.exports = structures
|
|
@ -0,0 +1,3 @@
|
|||
import "../mocks"
|
||||
|
||||
export * as koa from "./koa"
|
|
@ -1,5 +0,0 @@
|
|||
const { createMockContext } = require("@shopify/jest-koa-mocks")
|
||||
|
||||
exports.newContext = () => {
|
||||
return createMockContext()
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { createMockContext } from "@shopify/jest-koa-mocks"
|
||||
|
||||
export const newContext = () => {
|
||||
return createMockContext()
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
module.exports = require("./src/tests/utilities")
|
|
@ -0,0 +1 @@
|
|||
export * from "./src/tests/utilities"
|
File diff suppressed because it is too large
Load Diff
|
@ -143,6 +143,7 @@
|
|||
"@babel/core": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.4",
|
||||
"@budibase/standard-components": "^0.9.139",
|
||||
"@budibase/types": "^1.0.126-alpha.0",
|
||||
"@jest/test-sequencer": "^24.8.0",
|
||||
"@types/apidoc": "^0.50.0",
|
||||
"@types/bull": "^3.15.1",
|
||||
|
|
|
@ -52,6 +52,7 @@ const {
|
|||
import { getUniqueRows } from "../../utilities/usageQuota/rows"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import { errors, events } from "@budibase/backend-core"
|
||||
import { App } from "@budibase/types"
|
||||
|
||||
const URL_REGEX_SLASH = /\/|\\/g
|
||||
|
||||
|
@ -233,7 +234,7 @@ const performAppCreate = async (ctx: any) => {
|
|||
const apps = await getAllApps({ dev: true })
|
||||
const name = ctx.request.body.name
|
||||
checkAppName(ctx, apps, name)
|
||||
const url = exports.getAppUrl(ctx)
|
||||
const url = getAppUrl(ctx)
|
||||
checkAppUrl(ctx, apps, url)
|
||||
|
||||
const { useTemplate, templateKey, templateString } = ctx.request.body
|
||||
|
@ -291,7 +292,7 @@ const performAppCreate = async (ctx: any) => {
|
|||
return newApplication
|
||||
}
|
||||
|
||||
const creationEvents = (request: any) => {
|
||||
const creationEvents = (request: any, app: App) => {
|
||||
let creationFns = []
|
||||
|
||||
const body = request.body
|
||||
|
@ -312,15 +313,15 @@ const creationEvents = (request: any) => {
|
|||
creationFns.push(events.app.created)
|
||||
|
||||
for (let fn of creationFns) {
|
||||
fn()
|
||||
fn(app)
|
||||
}
|
||||
}
|
||||
|
||||
const appPostCreate = async (ctx: any, appId: string) => {
|
||||
creationEvents(ctx.request)
|
||||
const appPostCreate = async (ctx: any, app: App) => {
|
||||
creationEvents(ctx.request, app)
|
||||
// app import & template creation
|
||||
if (ctx.request.body.useTemplate === "true") {
|
||||
const rows = await getUniqueRows([appId])
|
||||
const rows = await getUniqueRows([app.appId])
|
||||
const rowCount = rows ? rows.length : 0
|
||||
if (rowCount) {
|
||||
try {
|
||||
|
@ -330,7 +331,7 @@ const appPostCreate = async (ctx: any, appId: string) => {
|
|||
// this import resulted in row usage exceeding the quota
|
||||
// delete the app
|
||||
// skip pre and post steps as no rows have been added to quotas yet
|
||||
ctx.params.appId = appId
|
||||
ctx.params.appId = app.appId
|
||||
await destroyApp(ctx)
|
||||
}
|
||||
throw err
|
||||
|
@ -341,7 +342,7 @@ const appPostCreate = async (ctx: any, appId: string) => {
|
|||
|
||||
export const create = async (ctx: any) => {
|
||||
const newApplication = await quotas.addApp(() => performAppCreate(ctx))
|
||||
await appPostCreate(ctx, newApplication.appId)
|
||||
await appPostCreate(ctx, newApplication)
|
||||
ctx.body = newApplication
|
||||
ctx.status = 200
|
||||
}
|
||||
|
@ -355,16 +356,16 @@ export const update = async (ctx: any) => {
|
|||
if (name) {
|
||||
checkAppName(ctx, apps, name, ctx.params.appId)
|
||||
}
|
||||
const url = await exports.getAppUrl(ctx)
|
||||
const url = getAppUrl(ctx)
|
||||
if (url) {
|
||||
checkAppUrl(ctx, apps, url, ctx.params.appId)
|
||||
ctx.request.body.url = url
|
||||
}
|
||||
|
||||
const data = await updateAppPackage(ctx.request.body, ctx.params.appId)
|
||||
events.app.updated()
|
||||
const app = await updateAppPackage(ctx.request.body, ctx.params.appId)
|
||||
events.app.updated(app)
|
||||
ctx.status = 200
|
||||
ctx.body = data
|
||||
ctx.body = app
|
||||
}
|
||||
|
||||
export const updateClient = async (ctx: any) => {
|
||||
|
@ -384,10 +385,10 @@ export const updateClient = async (ctx: any) => {
|
|||
version: packageJson.version,
|
||||
revertableVersion: currentVersion,
|
||||
}
|
||||
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||
events.app.versionUpdated()
|
||||
const app = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||
events.app.versionUpdated(app)
|
||||
ctx.status = 200
|
||||
ctx.body = data
|
||||
ctx.body = app
|
||||
}
|
||||
|
||||
export const revertClient = async (ctx: any) => {
|
||||
|
@ -408,10 +409,10 @@ export const revertClient = async (ctx: any) => {
|
|||
version: application.revertableVersion,
|
||||
revertableVersion: null,
|
||||
}
|
||||
const data = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||
events.app.versionReverted()
|
||||
const app = await updateAppPackage(appPackageUpdates, ctx.params.appId)
|
||||
events.app.versionReverted(app)
|
||||
ctx.status = 200
|
||||
ctx.body = data
|
||||
ctx.body = app
|
||||
}
|
||||
|
||||
const destroyApp = async (ctx: any) => {
|
||||
|
@ -423,14 +424,15 @@ const destroyApp = async (ctx: any) => {
|
|||
}
|
||||
|
||||
const db = isUnpublish ? getProdAppDB() : getAppDB()
|
||||
const app = await db.get(DocumentTypes.APP_METADATA)
|
||||
const result = await db.destroy()
|
||||
|
||||
if (isUnpublish) {
|
||||
await quotas.removePublishedApp()
|
||||
events.app.unpublished()
|
||||
events.app.unpublished(app)
|
||||
} else {
|
||||
await quotas.removeApp()
|
||||
events.app.deleted()
|
||||
events.app.deleted(app)
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
@ -531,10 +533,10 @@ const updateAppPackage = async (appPackage: any, appId: any) => {
|
|||
// Redis, shouldn't ever store it
|
||||
delete newAppPackage.lockedBy
|
||||
|
||||
const response = await db.put(newAppPackage)
|
||||
await db.put(newAppPackage)
|
||||
// remove any cached metadata, so that it will be updated
|
||||
await appCache.invalidateAppMetadata(appId)
|
||||
return response
|
||||
return newAppPackage
|
||||
}
|
||||
|
||||
const createEmptyAppPackage = async (ctx: any, app: any) => {
|
||||
|
|
|
@ -123,6 +123,7 @@ async function deployApp(deployment: any) {
|
|||
console.log("Deployed app initialised, setting deployment to successful")
|
||||
deployment.setStatus(DeploymentStatus.SUCCESS)
|
||||
await storeDeploymentHistory(deployment)
|
||||
return appDoc
|
||||
} catch (err: any) {
|
||||
deployment.setStatus(DeploymentStatus.FAILURE, err.message)
|
||||
await storeDeploymentHistory(deployment)
|
||||
|
@ -187,13 +188,14 @@ const _deployApp = async function (ctx: any) {
|
|||
|
||||
console.log("Deploying app...")
|
||||
|
||||
let app
|
||||
if (await isFirstDeploy()) {
|
||||
await quotas.addPublishedApp(() => deployApp(deployment))
|
||||
app = await quotas.addPublishedApp(() => deployApp(deployment))
|
||||
} else {
|
||||
await deployApp(deployment)
|
||||
app = await deployApp(deployment)
|
||||
}
|
||||
|
||||
events.app.published()
|
||||
events.app.published(app)
|
||||
ctx.body = deployment
|
||||
}
|
||||
|
||||
|
|
|
@ -84,9 +84,9 @@ export class RestImporter {
|
|||
const count = successQueries.length
|
||||
const importSource = this.source.getImportSource()
|
||||
const datasource = await db.get(datasourceId)
|
||||
events.query.import(datasource, importSource, count)
|
||||
events.query.imported(datasource, importSource, count)
|
||||
for (let query of successQueries) {
|
||||
events.query.created(query)
|
||||
events.query.created(datasource, query)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -106,8 +106,8 @@ describe("Rest Importer", () => {
|
|||
const importResult = await restImporter.importQueries(datasource._id)
|
||||
expect(importResult.errorQueries.length).toBe(0)
|
||||
expect(importResult.queries.length).toBe(assertions[key].count)
|
||||
expect(events.query.import).toBeCalledTimes(1)
|
||||
expect(events.query.import).toBeCalledWith(datasource, assertions[key].source, assertions[key].count)
|
||||
expect(events.query.imported).toBeCalledTimes(1)
|
||||
expect(events.query.imported).toBeCalledWith(datasource, assertions[key].source, assertions[key].count)
|
||||
jest.clearAllMocks()
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ export async function handleDataImport(user: any, table: any, dataImport: any) {
|
|||
}
|
||||
|
||||
await quotas.addRows(finalData.length, () => db.bulkDocs(finalData))
|
||||
events.row.import(table, "csv", finalData.length)
|
||||
events.row.imported(table, "csv", finalData.length)
|
||||
return table
|
||||
}
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ describe("/applications", () => {
|
|||
.set(config.defaultHeaders())
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(res.body.rev).toBeDefined()
|
||||
expect(res.body._rev).toBeDefined()
|
||||
expect(events.app.updated).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
@ -201,7 +201,7 @@ describe("/applications", () => {
|
|||
.set(headers)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(res.body.rev).toBeDefined()
|
||||
expect(res.body._rev).toBeDefined()
|
||||
// retrieve the app to check it
|
||||
const getRes = await request
|
||||
.get(`/api/applications/${config.getAppId()}/appPackage`)
|
||||
|
|
|
@ -55,8 +55,8 @@ describe("/tables", () => {
|
|||
expect(events.table.created).toBeCalledWith(res.body)
|
||||
expect(events.table.imported).toBeCalledTimes(1)
|
||||
expect(events.table.imported).toBeCalledWith(res.body, "csv")
|
||||
expect(events.row.import).toBeCalledTimes(1)
|
||||
expect(events.row.import).toBeCalledWith(res.body, "csv", 1)
|
||||
expect(events.row.imported).toBeCalledTimes(1)
|
||||
expect(events.row.imported).toBeCalledWith(res.body, "csv", 1)
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
|
@ -163,8 +163,8 @@ describe("/tables", () => {
|
|||
.expect(200)
|
||||
|
||||
expect(events.table.created).not.toHaveBeenCalled()
|
||||
expect(events.row.import).toBeCalledTimes(1)
|
||||
expect(events.row.import).toBeCalledWith(table, "csv", 1)
|
||||
expect(events.row.imported).toBeCalledTimes(1)
|
||||
expect(events.row.imported).toBeCalledWith(table, "csv", 1)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": ["es2019"],
|
||||
"lib": ["es2020"],
|
||||
"allowJs": true,
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"author": "Budibase",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"build": "rimraf dist/ && tsc -p tsconfig.json"
|
||||
"build": "rimraf dist/ && tsc"
|
||||
},
|
||||
"jest": {
|
||||
},
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
export interface App {}
|
||||
export interface App {
|
||||
appId: string
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"lib": ["es2019"],
|
||||
"lib": ["es2020"],
|
||||
"allowJs": true,
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"incremental": true
|
||||
"incremental": true,
|
||||
"types": [ "node", "jest"],
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
|
|
|
@ -1297,6 +1297,13 @@ async-hook-jl@^1.7.6:
|
|||
dependencies:
|
||||
stack-chain "^1.3.7"
|
||||
|
||||
async@~2.1.4:
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc"
|
||||
integrity sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=
|
||||
dependencies:
|
||||
lodash "^4.14.0"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
@ -2879,6 +2886,23 @@ globby@^11.0.4:
|
|||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
google-auth-library@~0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e"
|
||||
integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24=
|
||||
dependencies:
|
||||
gtoken "^1.2.1"
|
||||
jws "^3.1.4"
|
||||
lodash.noop "^3.0.1"
|
||||
request "^2.74.0"
|
||||
|
||||
google-p12-pem@^0.1.0:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177"
|
||||
integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=
|
||||
dependencies:
|
||||
node-forge "^0.7.1"
|
||||
|
||||
googleapis@^16.0.0:
|
||||
version "16.1.0"
|
||||
resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576"
|
||||
|
@ -2927,6 +2951,16 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.4:
|
|||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
|
||||
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
||||
|
||||
gtoken@^1.2.1:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8"
|
||||
integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w==
|
||||
dependencies:
|
||||
google-p12-pem "^0.1.0"
|
||||
jws "^3.0.0"
|
||||
mime "^1.4.1"
|
||||
request "^2.72.0"
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
|
@ -3986,7 +4020,7 @@ jwa@^1.4.1:
|
|||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^3.2.2:
|
||||
jws@^3.0.0, jws@^3.1.4, jws@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
|
||||
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
|
||||
|
@ -4306,6 +4340,11 @@ lodash.memoize@4.x:
|
|||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.noop@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c"
|
||||
integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=
|
||||
|
||||
lodash.once@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||
|
@ -4316,7 +4355,7 @@ lodash.pick@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
|
||||
|
||||
lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0:
|
||||
lodash@^4.14.0, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.7.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
@ -4435,6 +4474,11 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
|
|||
dependencies:
|
||||
mime-db "1.51.0"
|
||||
|
||||
mime@^1.4.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
mime@^2.5.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
|
||||
|
@ -4541,6 +4585,11 @@ node-fetch@2.6.7, node-fetch@^2.6.1:
|
|||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-forge@^0.7.1:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac"
|
||||
integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==
|
||||
|
||||
node-gyp-build@~4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb"
|
||||
|
@ -5502,7 +5551,7 @@ remove-trailing-slash@^0.1.1:
|
|||
resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d"
|
||||
integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==
|
||||
|
||||
request@^2.88.0:
|
||||
request@^2.72.0, request@^2.74.0, request@^2.88.0:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
|
@ -5931,6 +5980,11 @@ string-length@^4.0.1:
|
|||
char-regex "^1.0.2"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
string-template@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96"
|
||||
integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y=
|
||||
|
||||
string-width@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||
|
|
Loading…
Reference in New Issue