Updating with a tested and functional API for uploading files for configs.

This commit is contained in:
mike12345567 2021-05-07 13:55:30 +01:00
parent 1d435013b8
commit 4e3bc326b4
8 changed files with 78 additions and 893 deletions

View File

@ -38,6 +38,9 @@ static_resources:
route: route:
cluster: server-dev cluster: server-dev
# the below three cases are needed to make sure
# all traffic prefixed for the builder is passed through
# correctly.
- match: { path: "/" } - match: { path: "/" }
route: route:
cluster: builder-dev cluster: builder-dev

View File

@ -9,7 +9,7 @@ const { join } = require("path")
const fs = require("fs") const fs = require("fs")
const env = require("../environment") const env = require("../environment")
const { budibaseTempDir, ObjectStoreBuckets } = require("./utils") const { budibaseTempDir, ObjectStoreBuckets } = require("./utils")
const uuid = require("uuid/v4") const { v4 } = require("uuid")
const streamPipeline = promisify(stream.pipeline) const streamPipeline = promisify(stream.pipeline)
// use this as a temporary store of buckets that are being created // use this as a temporary store of buckets that are being created
@ -44,7 +44,7 @@ function publicPolicy(bucketName) {
} }
} }
const PUBLIC_BUCKETS = [ObjectStoreBuckets.APPS] const PUBLIC_BUCKETS = [ObjectStoreBuckets.APPS, ObjectStoreBuckets.GLOBAL]
/** /**
* Gets a connection to the object store using the S3 SDK. * Gets a connection to the object store using the S3 SDK.
@ -173,7 +173,7 @@ exports.retrieve = async (bucket, filepath) => {
*/ */
exports.retrieveToTmp = async (bucket, filepath) => { exports.retrieveToTmp = async (bucket, filepath) => {
const data = await exports.retrieve(bucket, filepath) const data = await exports.retrieve(bucket, filepath)
const outputPath = join(budibaseTempDir(), uuid()) const outputPath = join(budibaseTempDir(), v4())
fs.writeFileSync(outputPath, data) fs.writeFileSync(outputPath, data)
return outputPath return outputPath
} }

View File

@ -5,6 +5,7 @@ exports.ObjectStoreBuckets = {
BACKUPS: "backups", BACKUPS: "backups",
APPS: "prod-budi-app-assets", APPS: "prod-budi-app-assets",
TEMPLATES: "templates", TEMPLATES: "templates",
GLOBAL: "global",
} }
exports.budibaseTempDir = function () { exports.budibaseTempDir = function () {

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ const send = require("koa-send")
const { resolve, join } = require("../../../utilities/centralPath") const { resolve, join } = require("../../../utilities/centralPath")
const fetch = require("node-fetch") const fetch = require("node-fetch")
const uuid = require("uuid") const uuid = require("uuid")
const { ObjectStoreBuckets } = require("@budibase/auth").objectStore
const { prepareUpload } = require("../deploy/utils") const { prepareUpload } = require("../deploy/utils")
const { processString } = require("@budibase/string-templates") const { processString } = require("@budibase/string-templates")
const { budibaseTempDir } = require("../../../utilities/budibaseDir") const { budibaseTempDir } = require("../../../utilities/budibaseDir")
@ -15,7 +16,6 @@ const {
TOP_LEVEL_PATH, TOP_LEVEL_PATH,
} = require("../../../utilities/fileSystem") } = require("../../../utilities/fileSystem")
const env = require("../../../environment") const env = require("../../../environment")
// const fileProcessor = require("../../../utilities/fileSystem/processor")
const { objectStoreUrl, clientLibraryPath } = require("../../../utilities") const { objectStoreUrl, clientLibraryPath } = require("../../../utilities")
async function checkForSelfHostedURL(ctx) { async function checkForSelfHostedURL(ctx) {
@ -48,17 +48,10 @@ exports.uploadFile = async function (ctx) {
// filenames converted to UUIDs so they are unique // filenames converted to UUIDs so they are unique
const processedFileName = `${uuid.v4()}.${fileExtension}` const processedFileName = `${uuid.v4()}.${fileExtension}`
// need to handle image processing
// TODO either offer this as an option, or don't do it at all
// await fileProcessor.process({
// ...file,
// extension: fileExtension,
// })
return prepareUpload({ return prepareUpload({
file, file,
s3Key: `assets/${ctx.appId}/attachments/${processedFileName}`, s3Key: `assets/${ctx.appId}/attachments/${processedFileName}`,
bucket: "prod-budi-app-assets", bucket: ObjectStoreBuckets.APPS,
}) })
}) })

View File

@ -10,6 +10,7 @@ const fetch = require("node-fetch")
const { Configs } = require("../../../constants") const { Configs } = require("../../../constants")
const email = require("../../../utilities/email") const email = require("../../../utilities/email")
const env = require("../../../environment") const env = require("../../../environment")
const { upload, ObjectStoreBuckets } = require("@budibase/auth").objectStore
const APP_PREFIX = "app_" const APP_PREFIX = "app_"
@ -94,6 +95,46 @@ exports.find = async function (ctx) {
} }
} }
exports.upload = async function (ctx) {
if (ctx.request.files == null || ctx.request.files.file.length > 1) {
ctx.throw(400, "One file must be uploaded.")
}
const file = ctx.request.files.file
const { type, name } = ctx.params
const fileExtension = [...file.name.split(".")].pop()
// filenames converted to UUIDs so they are unique
const processedFileName = `${name}.${fileExtension}`
const bucket = ObjectStoreBuckets.GLOBAL
const key = `${type}/${processedFileName}`
await upload({
bucket,
filename: key,
path: file.path,
type: file.type,
})
// add to configuration structure
// TODO: right now this only does a global level
const db = new CouchDB(GLOBAL_DB)
let config = await getScopedFullConfig(db, { type })
if (!config) {
config = {
_id: generateConfigID({ type }),
}
}
const url = `/${bucket}/${key}`
config[`${name}Url`] = url
// write back to db with url updated
await db.put(config)
ctx.body = {
message: "File has been uploaded and url stored to config.",
url,
}
}
exports.destroy = async function (ctx) { exports.destroy = async function (ctx) {
const db = new CouchDB(GLOBAL_DB) const db = new CouchDB(GLOBAL_DB)
const { id, rev } = ctx.params const { id, rev } = ctx.params

View File

@ -2,7 +2,7 @@ const Router = require("@koa/router")
const controller = require("../../controllers/admin/configs") const controller = require("../../controllers/admin/configs")
const joiValidator = require("../../../middleware/joi-validator") const joiValidator = require("../../../middleware/joi-validator")
const Joi = require("joi") const Joi = require("joi")
const { Configs } = require("../../../constants") const { Configs, ConfigUploads } = require("../../../constants")
const router = Router() const router = Router()
@ -61,6 +61,14 @@ function buildConfigSaveValidation() {
) )
} }
function buildUploadValidation() {
// prettier-ignore
return joiValidator.params(Joi.object({
type: Joi.string().valid(...Object.values(Configs)).required(),
name: Joi.string().valid(...Object.values(ConfigUploads)).required(),
}).required())
}
function buildConfigGetValidation() { function buildConfigGetValidation() {
// prettier-ignore // prettier-ignore
return joiValidator.params(Joi.object({ return joiValidator.params(Joi.object({
@ -79,5 +87,10 @@ router
controller.fetch controller.fetch
) )
.get("/api/admin/configs/:type", buildConfigGetValidation(), controller.find) .get("/api/admin/configs/:type", buildConfigGetValidation(), controller.find)
.post(
"/api/admin/configs/upload/:type/:name",
buildUploadValidation(),
controller.upload
)
module.exports = router module.exports = router

View File

@ -17,6 +17,10 @@ exports.Configs = {
GOOGLE: "google", GOOGLE: "google",
} }
exports.ConfigUploads = {
LOGO: "logo",
}
const TemplateTypes = { const TemplateTypes = {
EMAIL: "email", EMAIL: "email",
} }