[BUGFIX] ObjectMetadata item server validation (#10699)
# Introduction This PR contains several SNAPSHOT files explaining big + While refactoring the Object Model settings page in https://github.com/twentyhq/twenty/pull/10653, encountered a critical issue when submitting either one or both names with `""` empty string hard corrupting a workspace. This motivate this PR reviewing server side validation I feel like we could share zod schema between front and back ## Refactored server validation What to expect from Names: - Plural and singular have to be different ( case insensitive and trimmed check ) - Contains only a-z A-Z and 0-9 - Follows camelCase - Is not empty => Is not too short ( 1 ) - Is not too long ( 63 ) - Is case insensitive( fooBar and fOoBar now rejected ) What to expect from Labels: - Plural and singular have to be different ( case insensitive and trimmed check ) - Is not empty => Is not too short ( 1 ) - Is not too long ( 63 ) - Is case insensitive ( fooBar and fOoBar now rejected ) close https://github.com/twentyhq/twenty/issues/10694 ## Creation integrations tests Created new integrations tests, following [EachTesting](https://jestjs.io/docs/api#testeachtablename-fn-timeout) pattern and uses snapshot to assert errors message. These tests cover several failing use cases and started to implement ones for the happy path but object metadata item deletion is currently broken unless I'm mistaken @Weiko is on it ## Notes - [ ] As we've added new validation rules towards names and labels we should scan db in order to standardize existing values using either a migration command or manual check - [ ] Will review in an other PR the update path, adding integrations tests and so on
This commit is contained in:
@ -41,12 +41,9 @@ import {
|
||||
RelationMetadataEntity,
|
||||
RelationMetadataType,
|
||||
} from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity';
|
||||
import { InvalidStringException } from 'src/engine/metadata-modules/utils/exceptions/invalid-string.exception';
|
||||
import { NameNotAvailableException } from 'src/engine/metadata-modules/utils/exceptions/name-not-available.exception';
|
||||
import { NameTooLongException } from 'src/engine/metadata-modules/utils/exceptions/name-too-long.exception';
|
||||
import { exceedsDatabaseIdentifierMaximumLength } from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils';
|
||||
import { validateFieldNameAvailabilityOrThrow } from 'src/engine/metadata-modules/utils/validate-field-name-availability.utils';
|
||||
import { validateMetadataNameValidityOrThrow as validateFieldNameValidityOrThrow } from 'src/engine/metadata-modules/utils/validate-metadata-name-validity.utils';
|
||||
import { validateMetadataNameOrThrow } from 'src/engine/metadata-modules/utils/validate-metadata-name.utils';
|
||||
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
|
||||
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
|
||||
import {
|
||||
@ -62,6 +59,7 @@ import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import { ViewService } from 'src/modules/view/services/view.service';
|
||||
import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity';
|
||||
import { InvalidMetadataNameException } from 'src/engine/metadata-modules/utils/exceptions/invalid-metadata-name.exception';
|
||||
|
||||
import { FieldMetadataValidationService } from './field-metadata-validation.service';
|
||||
import { FieldMetadataEntity } from './field-metadata.entity';
|
||||
@ -540,30 +538,32 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
): T {
|
||||
if (fieldMetadataInput.name) {
|
||||
try {
|
||||
validateFieldNameValidityOrThrow(fieldMetadataInput.name);
|
||||
validateMetadataNameOrThrow(fieldMetadataInput.name);
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidMetadataNameException) {
|
||||
throw new FieldMetadataException(
|
||||
error.message,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
validateFieldNameAvailabilityOrThrow(
|
||||
fieldMetadataInput.name,
|
||||
objectMetadata,
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidStringException) {
|
||||
throw new FieldMetadataException(
|
||||
`Characters used in name "${fieldMetadataInput.name}" are not supported`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
} else if (error instanceof NameTooLongException) {
|
||||
throw new FieldMetadataException(
|
||||
`Name "${fieldMetadataInput.name}" exceeds 63 characters`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
} else if (error instanceof NameNotAvailableException) {
|
||||
if (error instanceof InvalidMetadataNameException) {
|
||||
throw new FieldMetadataException(
|
||||
`Name "${fieldMetadataInput.name}" is not available, check that it is not duplicating another field's name.`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user