Merge pull request #684 from mz8i/fix/681-land-use-edit

Allow non-editable fields to be auto-derived
This commit is contained in:
Maciej Ziarkowski 2021-08-12 01:32:06 +01:00 committed by GitHub
commit 806e1f6e74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 5 deletions

View File

@ -3,10 +3,19 @@ import { valueType } from '../../helpers';
/** Configuration for a single data field */
export interface DataFieldConfig {
/**
* Allow editing the field?
* Allow editing the field through the API?
*/
edit: boolean;
/**
* Should the editing of the field be allowed - but only when
* the change is a result of an edit of another field, from which this field is derived.
* Example: editing Land Use Group modifies Land Use Order, too, because LU Order is automatically derived from LU Group.
* But Land Use Order itself cannot be modified directly by users.
* Default: false
*/
derivedEdit?: boolean;
/**
* Allow verifying the field value?
* Default: false;
@ -236,6 +245,7 @@ export const dataFieldsConfig = valueType<DataFieldConfig>()({ /* eslint-disable
},
current_landuse_order: {
edit: false,
derivedEdit: true,
verify: false,
},

View File

@ -55,7 +55,7 @@ export async function insertEditHistoryRevision(
const columnConfigLookup = Object.assign(
{},
...Object.entries(dataFieldsConfig).filter(([, config]) => config.edit).map(([key, {
...Object.entries(dataFieldsConfig).filter(([, config]) => config.edit || config.derivedEdit).map(([key, {
asJson = false,
sqlCast
}]) => ({ [key]: {

View File

@ -21,6 +21,15 @@ export class InvalidOperationError extends UserError {
}
}
export class InvalidFieldError extends UserError {
public fieldName: string;
constructor(message?: string, fieldName?: string) {
super(message);
this.name = 'InvalidFieldError';
this.fieldName = fieldName;
}
}
export class FieldTypeError extends UserError {
public fieldName: string;
constructor(message?: string, fieldName?: string) {

View File

@ -31,7 +31,11 @@ export async function getBuildingById(id: number) {
}
}
const FIELD_EDIT_WHITELIST = new Set(Object.entries(dataFieldsConfig).filter(([, value]) => value.edit).map(([key]) => key));
/**
* List of fields for which modification is allowed
* (directly by the user, or for fields that are derived from others)
*/
const FINAL_FIELD_EDIT_ALLOWLIST = new Set(Object.entries(dataFieldsConfig).filter(([, value]) => value.edit || value.derivedEdit).map(([key]) => key));
export async function editBuilding(buildingId: number, building: any, userId: string): Promise<object> { // TODO add proper building type
return await updateBuildingData(buildingId, userId, async () => {
@ -44,7 +48,7 @@ export async function editBuilding(buildingId: number, building: any, userId: st
delete processedBuilding.geometry_id;
// return whitelisted fields to update
return pickFields(processedBuilding, FIELD_EDIT_WHITELIST);
return pickFields(processedBuilding, FINAL_FIELD_EDIT_ALLOWLIST);
});
}

View File

@ -2,7 +2,8 @@ import Ajv from 'ajv';
import addFormats from 'ajv-formats';
import { mapObject } from '../../../helpers';
import { FieldTypeError } from '../../errors/general';
import { InvalidFieldError, FieldTypeError } from '../../errors/general';
import { dataFieldsConfig } from '../../config/dataFields';
import { fieldSchemaConfig } from '../../config/fieldSchemaConfig';
const ajv = new Ajv();
@ -10,8 +11,14 @@ addFormats(ajv);
const compiledSchemas = mapObject(fieldSchemaConfig, ([, val]) => ajv.compile(val))
const EXTERNAL_FIELD_EDIT_ALLOWLIST = new Set(Object.entries(dataFieldsConfig).filter(([, value]) => value.edit).map(([key]) => key));
export function validateBuildingUpdate(buildingId: number, building: any) {
for(const field of Object.keys(building)) {
if(!EXTERNAL_FIELD_EDIT_ALLOWLIST.has(field)) {
throw new InvalidFieldError('Field is not editable', field);
}
if(field in compiledSchemas) {
if(!compiledSchemas[field](building[field])) {
throw new FieldTypeError('Invalid format of data sent', field);