From 194b76985c0a434e6ff7ba746101447e80075aec Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 26 Apr 2022 14:24:51 +0100 Subject: [PATCH] Fix for #5269 - the sub type was being lost in some scenarios related to the user table being updated - making sure it is consistently kept when dealing with either of the related tables. --- .../src/api/controllers/table/internal.js | 26 +++++++++++++++- packages/server/src/constants/index.js | 8 +++++ .../src/db/linkedRows/LinkController.js | 1 + .../src/utilities/rowProcessor/index.js | 21 +++++++------ .../src/utilities/rowProcessor/utils.js | 30 ++++++++++++++++++- 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/table/internal.js b/packages/server/src/api/controllers/table/internal.js index 476e7a52af..412f644059 100644 --- a/packages/server/src/api/controllers/table/internal.js +++ b/packages/server/src/api/controllers/table/internal.js @@ -10,9 +10,30 @@ const { const usageQuota = require("../../../utilities/usageQuota") const { getAppDB } = require("@budibase/backend-core/context") const env = require("../../../environment") -const { cleanupAttachments } = require("../../../utilities/rowProcessor") +const { + cleanupAttachments, + fixAutoColumnSubType, +} = require("../../../utilities/rowProcessor") const { runStaticFormulaChecks } = require("./bulkFormula") +function checkAutoColumns(table, oldTable) { + if (!table.schema) { + return table + } + for (let [key, schema] of Object.entries(table.schema)) { + if (!schema.autocolumn || schema.subtype) { + continue + } + const oldSchema = oldTable.schema[key] + if (oldSchema && oldSchema.subtype) { + table.schema[key].subtype = oldSchema.subtype + } else { + table.schema[key] = fixAutoColumnSubType(schema) + } + } + return table +} + exports.save = async function (ctx) { const db = getAppDB() const { dataImport, ...rest } = ctx.request.body @@ -29,9 +50,12 @@ exports.save = async function (ctx) { oldTable = await db.get(ctx.request.body._id) } + // check all types are correct if (hasTypeChanged(tableToSave, oldTable)) { ctx.throw(400, "A column type has changed.") } + // check that subtypes have been maintained + tableToSave = checkAutoColumns(tableToSave, oldTable) // saving a table is a complex operation, involving many different steps, this // has been broken out into a utility to make it more obvious/easier to manipulate diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js index cf89f1fe99..c08621cb8a 100644 --- a/packages/server/src/constants/index.js +++ b/packages/server/src/constants/index.js @@ -162,6 +162,14 @@ exports.AutoFieldSubTypes = { 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", diff --git a/packages/server/src/db/linkedRows/LinkController.js b/packages/server/src/db/linkedRows/LinkController.js index 86c32bf94f..32782df162 100644 --- a/packages/server/src/db/linkedRows/LinkController.js +++ b/packages/server/src/db/linkedRows/LinkController.js @@ -376,6 +376,7 @@ class LinkController { if (field.autocolumn) { linkedField.autocolumn = field.autocolumn + linkedField.subtype = field.subtype } // check the linked table to make sure we aren't overwriting an existing column diff --git a/packages/server/src/utilities/rowProcessor/index.js b/packages/server/src/utilities/rowProcessor/index.js index 18e0b14de6..36a02eb9b1 100644 --- a/packages/server/src/utilities/rowProcessor/index.js +++ b/packages/server/src/utilities/rowProcessor/index.js @@ -2,7 +2,7 @@ const linkRows = require("../../db/linkedRows") const { cloneDeep } = require("lodash/fp") const { FieldTypes, AutoFieldSubTypes } = require("../../constants") const { attachmentsRelativeURL } = require("../index") -const { processFormulas } = require("./utils") +const { processFormulas, fixAutoColumnSubType } = require("./utils") const { deleteFiles } = require("../../utilities/fileSystem/utilities") const { ObjectStoreBuckets } = require("../../constants") const { @@ -11,6 +11,7 @@ const { dbExists, } = require("@budibase/backend-core/db") const { getAppId } = require("@budibase/backend-core/context") +const { InternalTables } = require("../../db/utils") const BASE_AUTO_ID = 1 @@ -137,21 +138,23 @@ function processAutoColumn( opts = { reprocessing: false, noAutoRelationships: false } ) { let noUser = !user || !user.userId + let isUserTable = table._id === InternalTables.USER_METADATA let now = new Date().toISOString() // if a row doesn't have a revision then it doesn't exist yet const creating = !row._rev + // check its not user table, or whether any of the processing options have been disabled + const shouldUpdateUserFields = + !isUserTable && !opts.reprocessing && !opts.noAutoRelationships && !noUser for (let [key, schema] of Object.entries(table.schema)) { if (!schema.autocolumn) { continue } + if (!schema.subtype) { + schema = fixAutoColumnSubType(schema) + } switch (schema.subtype) { case AutoFieldSubTypes.CREATED_BY: - if ( - creating && - !opts.reprocessing && - !opts.noAutoRelationships && - !noUser - ) { + if (creating && shouldUpdateUserFields) { row[key] = [user.userId] } break @@ -161,7 +164,7 @@ function processAutoColumn( } break case AutoFieldSubTypes.UPDATED_BY: - if (!opts.reprocessing && !opts.noAutoRelationships && !noUser) { + if (shouldUpdateUserFields) { row[key] = [user.userId] } break @@ -179,7 +182,7 @@ function processAutoColumn( return { table, row } } exports.processAutoColumn = processAutoColumn - +exports.fixAutoColumnSubType = fixAutoColumnSubType exports.processFormulas = processFormulas /** diff --git a/packages/server/src/utilities/rowProcessor/utils.js b/packages/server/src/utilities/rowProcessor/utils.js index 95b7828084..262ef40a3a 100644 --- a/packages/server/src/utilities/rowProcessor/utils.js +++ b/packages/server/src/utilities/rowProcessor/utils.js @@ -1,6 +1,34 @@ -const { FieldTypes, FormulaTypes } = require("../../constants") +const { + FieldTypes, + FormulaTypes, + AutoFieldDefaultNames, + AutoFieldSubTypes, +} = require("../../constants") const { processStringSync } = require("@budibase/string-templates") +/** + * If the subtype has been lost for any reason this works out what + * subtype the auto column should be. + */ +exports.fixAutoColumnSubType = column => { + if (!column.autocolumn || !column.name || column.subtype) { + return column + } + // the columns which get auto generated + if (column.name.endsWith(AutoFieldDefaultNames.CREATED_BY)) { + column.subtype = AutoFieldSubTypes.CREATED_BY + } else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_BY)) { + column.subtype = AutoFieldSubTypes.UPDATED_BY + } else if (column.name.endsWith(AutoFieldDefaultNames.CREATED_AT)) { + column.subtype = AutoFieldSubTypes.CREATED_AT + } else if (column.name.endsWith(AutoFieldDefaultNames.UPDATED_AT)) { + column.subtype = AutoFieldSubTypes.UPDATED_AT + } else if (column.name.endsWith(AutoFieldDefaultNames.AUTO_ID)) { + column.subtype = AutoFieldSubTypes.AUTO_ID + } + return column +} + /** * Looks through the rows provided and finds formulas - which it then processes. */