Updating to handle prod vs dev apps and deletion of attachments, as well as handling it on update.

This commit is contained in:
mike12345567 2022-01-06 18:45:40 +00:00
parent f1981220af
commit c75cc47ad3
2 changed files with 45 additions and 9 deletions

View File

@ -26,6 +26,7 @@ const {
getFromDesignDoc, getFromDesignDoc,
getFromMemoryDoc, getFromMemoryDoc,
} = require("../view/utils") } = require("../view/utils")
const { cloneDeep } = require("lodash/fp")
const CALCULATION_TYPES = { const CALCULATION_TYPES = {
SUM: "sum", SUM: "sum",
@ -110,14 +111,14 @@ exports.patch = async ctx => {
const inputs = ctx.request.body const inputs = ctx.request.body
const tableId = inputs.tableId const tableId = inputs.tableId
const isUserTable = tableId === InternalTables.USER_METADATA const isUserTable = tableId === InternalTables.USER_METADATA
let dbRow let oldRow
try { try {
dbRow = await db.get(inputs._id) oldRow = await db.get(inputs._id)
} catch (err) { } catch (err) {
if (isUserTable) { if (isUserTable) {
// don't include the rev, it'll be the global rev // don't include the rev, it'll be the global rev
// this time // this time
dbRow = { oldRow = {
_id: inputs._id, _id: inputs._id,
} }
} else { } else {
@ -126,13 +127,14 @@ exports.patch = async ctx => {
} }
let dbTable = await db.get(tableId) let dbTable = await db.get(tableId)
// need to build up full patch fields before coerce // need to build up full patch fields before coerce
let combinedRow = cloneDeep(oldRow)
for (let key of Object.keys(inputs)) { for (let key of Object.keys(inputs)) {
if (!dbTable.schema[key]) continue if (!dbTable.schema[key]) continue
dbRow[key] = inputs[key] combinedRow[key] = inputs[key]
} }
// this returns the table and row incase they have been updated // this returns the table and row incase they have been updated
let { table, row } = inputProcessing(ctx.user, dbTable, dbRow) let { table, row } = inputProcessing(ctx.user, dbTable, combinedRow)
const validateResult = await validate({ const validateResult = await validate({
row, row,
table, table,
@ -150,6 +152,8 @@ exports.patch = async ctx => {
tableId: row.tableId, tableId: row.tableId,
table, table,
}) })
// check if any attachments removed
await cleanupAttachments(appId, table, { oldRow, row })
if (isUserTable) { if (isUserTable) {
// the row has been updated, need to put it into the ctx // the row has been updated, need to put it into the ctx

View File

@ -5,6 +5,8 @@ const { attachmentsRelativeURL } = require("../index")
const { processFormulas } = require("./utils") const { processFormulas } = require("./utils")
const { deleteFiles } = require("../../utilities/fileSystem/utilities") const { deleteFiles } = require("../../utilities/fileSystem/utilities")
const { ObjectStoreBuckets } = require("../../constants") const { ObjectStoreBuckets } = require("../../constants")
const { isProdAppID, getDeployedAppID, dbExists } = require("@budibase/auth/db")
const CouchDB = require("../../db")
const BASE_AUTO_ID = 1 const BASE_AUTO_ID = 1
@ -97,6 +99,23 @@ const TYPE_TRANSFORM_MAP = {
}, },
} }
/**
* Given the old state of the row and the new one after an update, this will
* find the keys that have been removed in the updated row.
*/
function getRemovedAttachmentKeys(oldRow, row, attachmentKey) {
if (!oldRow[attachmentKey]) {
return []
}
const oldKeys = oldRow[attachmentKey].map(attachment => attachment.key)
// no attachments in new row, all removed
if (!row[attachmentKey]) {
return oldKeys
}
const newKeys = row[attachmentKey].map(attachment => attachment.key)
return oldKeys.filter(key => newKeys.indexOf(key) === -1)
}
/** /**
* This will update any auto columns that are found on the row/table with the correct information based on * This will update any auto columns that are found on the row/table with the correct information based on
* time now and the current logged in user making the request. * time now and the current logged in user making the request.
@ -281,10 +300,18 @@ exports.outputProcessing = async (
* @param {object} table The table from which a row is being removed. * @param {object} table The table from which a row is being removed.
* @param {any} row optional - the row being removed. * @param {any} row optional - the row being removed.
* @param {any} rows optional - if multiple rows being deleted can do this in bulk. * @param {any} rows optional - if multiple rows being deleted can do this in bulk.
* @param {any} oldRow optional - if updating a row this will determine the difference.
* @return {Promise<void>} When all attachments have been removed this will return. * @return {Promise<void>} When all attachments have been removed this will return.
*/ */
exports.cleanupAttachments = async (appId, table, {row, rows}) => { exports.cleanupAttachments = async (appId, table, { row, rows, oldRow }) => {
// TODO: check app ID version if (!isProdAppID(appId)) {
const prodAppId = getDeployedAppID(appId)
// if prod exists, then don't allow deleting
const exists = await dbExists(CouchDB, prodAppId)
if (exists) {
return
}
}
let files = [] let files = []
function addFiles(row, key) { function addFiles(row, key) {
if (row[key]) { if (row[key]) {
@ -295,11 +322,16 @@ exports.cleanupAttachments = async (appId, table, {row, rows}) => {
if (schema.type !== FieldTypes.ATTACHMENT) { if (schema.type !== FieldTypes.ATTACHMENT) {
continue continue
} }
if (row) { // if updating, need to manage the differences
if (oldRow && row) {
files = files.concat(getRemovedAttachmentKeys(oldRow, row, key))
} else if (row) {
addFiles(row, key) addFiles(row, key)
} else if (rows) { } else if (rows) {
rows.forEach(row => addFiles(row, key)) rows.forEach(row => addFiles(row, key))
} }
} }
if (files.length > 0) {
return deleteFiles(ObjectStoreBuckets.APPS, files) return deleteFiles(ObjectStoreBuckets.APPS, files)
}
} }