From c174ddc708ac3f80a270c844e980008751a27096 Mon Sep 17 00:00:00 2001 From: hexastack Date: Fri, 4 Apr 2025 15:46:51 +0100 Subject: [PATCH 1/5] fix: define a type for fields in ContentType schema --- .../content-type.controller.spec.ts | 11 ++++--- api/src/cms/dto/contentType.dto.ts | 7 +++-- api/src/cms/schemas/content-type.schema.ts | 10 +++--- .../validate-required-fields.validator.ts | 8 +++-- api/src/setting/schemas/types.ts | 17 +++++++++- api/src/utils/test/fixtures/contenttype.ts | 31 ++++++++++--------- 6 files changed, 51 insertions(+), 33 deletions(-) diff --git a/api/src/cms/controllers/content-type.controller.spec.ts b/api/src/cms/controllers/content-type.controller.spec.ts index 14dc871c..061d307e 100644 --- a/api/src/cms/controllers/content-type.controller.spec.ts +++ b/api/src/cms/controllers/content-type.controller.spec.ts @@ -13,6 +13,7 @@ import { AttachmentRepository } from '@/attachment/repositories/attachment.repos import { AttachmentModel } from '@/attachment/schemas/attachment.schema'; import { AttachmentService } from '@/attachment/services/attachment.service'; import { BlockService } from '@/chat/services/block.service'; +import { ContentTypeType } from '@/setting/schemas/types'; import { NOT_FOUND_ID } from '@/utils/constants/mock'; import { getUpdateOneError } from '@/utils/test/errors/messages'; import { installContentFixtures } from '@/utils/test/fixtures/content'; @@ -100,27 +101,27 @@ describe('ContentTypeController', () => { { name: 'address', label: 'Address', - type: 'text', + type: ContentTypeType.text, }, { name: 'image', label: 'Image', - type: 'file', + type: ContentTypeType.file, }, { name: 'description', label: 'Description', - type: 'html', + type: ContentTypeType.html, }, { name: 'rooms', label: 'Rooms', - type: 'file', + type: ContentTypeType.file, }, { name: 'price', label: 'Price', - type: 'file', + type: ContentTypeType.file, }, ], }; diff --git a/api/src/cms/dto/contentType.dto.ts b/api/src/cms/dto/contentType.dto.ts index f4f2ae25..33377af0 100644 --- a/api/src/cms/dto/contentType.dto.ts +++ b/api/src/cms/dto/contentType.dto.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -19,6 +19,7 @@ import { ValidateNested, } from 'class-validator'; +import { ContentTypeType } from '@/setting/schemas/types'; import { DtoConfig } from '@/utils/types/dto.types'; import { ValidateRequiredFields } from '../validators/validate-required-fields.validator'; @@ -34,11 +35,11 @@ export class FieldType { label: string; @IsString() - @IsEnum(['text', 'url', 'textarea', 'checkbox', 'file', 'html'], { + @IsEnum(ContentTypeType, { message: "type must be one of the following values: 'text', 'url', 'textarea', 'checkbox', 'file', 'html'", }) - type: string; + type: ContentTypeType; } export class ContentTypeCreateDto { diff --git a/api/src/cms/schemas/content-type.schema.ts b/api/src/cms/schemas/content-type.schema.ts index e1d95921..43970bfb 100644 --- a/api/src/cms/schemas/content-type.schema.ts +++ b/api/src/cms/schemas/content-type.schema.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -12,6 +12,8 @@ import mongoose from 'mongoose'; import { BaseSchema } from '@/utils/generics/base-schema'; import { LifecycleHookManager } from '@/utils/generics/lifecycle-hook-manager'; +import { FieldType } from '../dto/contentType.dto'; + @Schema({ timestamps: true }) export class ContentType extends BaseSchema { /** @@ -39,11 +41,7 @@ export class ContentType extends BaseSchema { }, ], }) - fields: { - name: string; - label: string; - type: string; - }[]; + fields: FieldType[]; } export const ContentTypeModel: ModelDefinition = LifecycleHookManager.attach({ diff --git a/api/src/cms/validators/validate-required-fields.validator.ts b/api/src/cms/validators/validate-required-fields.validator.ts index 4d7cae5b..75c372c9 100644 --- a/api/src/cms/validators/validate-required-fields.validator.ts +++ b/api/src/cms/validators/validate-required-fields.validator.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -12,6 +12,8 @@ import { ValidatorConstraintInterface, } from 'class-validator'; +import { ContentTypeType } from '@/setting/schemas/types'; + import { FieldType } from '../dto/contentType.dto'; @ValidatorConstraint({ name: 'validateRequiredFields', async: false }) @@ -20,12 +22,12 @@ export class ValidateRequiredFields implements ValidatorConstraintInterface { { name: 'title', label: 'Title', - type: 'text', + type: ContentTypeType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: ContentTypeType.checkbox, }, ]; diff --git a/api/src/setting/schemas/types.ts b/api/src/setting/schemas/types.ts index fbf30493..15232e64 100644 --- a/api/src/setting/schemas/types.ts +++ b/api/src/setting/schemas/types.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -20,6 +20,15 @@ export enum SettingType { multiple_attachment = 'multiple_attachment', } +export enum ContentTypeType { + text = 'text', + url = 'url', + textarea = 'textarea', + checkbox = 'checkbox', + file = 'file', + html = 'html', +} + /** * The following interfaces are declared, and currently not used * TextSetting @@ -128,3 +137,9 @@ export type AnySetting = | MultipleAttachmentSetting; export type SettingDict = { [group: string]: Setting[] }; + +export type Field = { + name: string; + label: string; + type: ContentTypeType; +}; diff --git a/api/src/utils/test/fixtures/contenttype.ts b/api/src/utils/test/fixtures/contenttype.ts index 8c295b05..577c8c6a 100644 --- a/api/src/utils/test/fixtures/contenttype.ts +++ b/api/src/utils/test/fixtures/contenttype.ts @@ -13,6 +13,7 @@ import { ContentType, ContentTypeModel, } from '@/cms/schemas/content-type.schema'; +import { ContentTypeType } from '@/setting/schemas/types'; import { getFixturesWithDefaultValues } from '../defaultValues'; import { FixturesTypeBuilder } from '../types'; @@ -27,12 +28,12 @@ export const contentTypeDefaultValues: TContentTypeFixtures['defaultValues'] = { { name: 'title', label: 'Title', - type: 'text', + type: ContentTypeType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: ContentTypeType.checkbox, }, ], }; @@ -44,27 +45,27 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: 'text', + type: ContentTypeType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: ContentTypeType.checkbox, }, { name: 'description', label: 'Description', - type: 'text', + type: ContentTypeType.text, }, { name: 'image', label: 'Image', - type: 'file', + type: ContentTypeType.file, }, { name: 'subtitle', label: 'Image', - type: 'file', + type: ContentTypeType.file, }, ], }, @@ -74,22 +75,22 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: 'text', + type: ContentTypeType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: ContentTypeType.checkbox, }, { name: 'address', label: 'Address', - type: 'text', + type: ContentTypeType.text, }, { name: 'image', label: 'Image', - type: 'file', + type: ContentTypeType.file, }, ], }, @@ -99,22 +100,22 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: 'text', + type: ContentTypeType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: ContentTypeType.checkbox, }, { name: 'address', label: 'Address', - type: 'text', + type: ContentTypeType.text, }, { name: 'image', label: 'Image', - type: 'file', + type: ContentTypeType.file, }, ], }, From de13301a542ce91771b209cefd1a16db91eabea9 Mon Sep 17 00:00:00 2001 From: hexastack Date: Mon, 7 Apr 2025 09:17:22 +0100 Subject: [PATCH 2/5] fix: apply feedback --- api/src/setting/schemas/types.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/api/src/setting/schemas/types.ts b/api/src/setting/schemas/types.ts index 15232e64..4de39331 100644 --- a/api/src/setting/schemas/types.ts +++ b/api/src/setting/schemas/types.ts @@ -137,9 +137,3 @@ export type AnySetting = | MultipleAttachmentSetting; export type SettingDict = { [group: string]: Setting[] }; - -export type Field = { - name: string; - label: string; - type: ContentTypeType; -}; From ca633b52fbec4ababee6b65a7f211c8ae05b2cb5 Mon Sep 17 00:00:00 2001 From: hexastack Date: Mon, 7 Apr 2025 12:59:21 +0100 Subject: [PATCH 3/5] fix: address review --- .../content-type.controller.spec.ts | 12 +++---- api/src/cms/dto/contentType.dto.ts | 17 ++++++---- api/src/cms/schemas/content-type.schema.ts | 4 +-- .../validate-required-fields.validator.ts | 12 +++---- api/src/setting/schemas/types.ts | 2 +- api/src/utils/test/fixtures/contenttype.ts | 32 +++++++++---------- 6 files changed, 41 insertions(+), 38 deletions(-) diff --git a/api/src/cms/controllers/content-type.controller.spec.ts b/api/src/cms/controllers/content-type.controller.spec.ts index 061d307e..da6044a3 100644 --- a/api/src/cms/controllers/content-type.controller.spec.ts +++ b/api/src/cms/controllers/content-type.controller.spec.ts @@ -13,7 +13,7 @@ import { AttachmentRepository } from '@/attachment/repositories/attachment.repos import { AttachmentModel } from '@/attachment/schemas/attachment.schema'; import { AttachmentService } from '@/attachment/services/attachment.service'; import { BlockService } from '@/chat/services/block.service'; -import { ContentTypeType } from '@/setting/schemas/types'; +import { FieldType } from '@/setting/schemas/types'; import { NOT_FOUND_ID } from '@/utils/constants/mock'; import { getUpdateOneError } from '@/utils/test/errors/messages'; import { installContentFixtures } from '@/utils/test/fixtures/content'; @@ -101,27 +101,27 @@ describe('ContentTypeController', () => { { name: 'address', label: 'Address', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'image', label: 'Image', - type: ContentTypeType.file, + type: FieldType.file, }, { name: 'description', label: 'Description', - type: ContentTypeType.html, + type: FieldType.html, }, { name: 'rooms', label: 'Rooms', - type: ContentTypeType.file, + type: FieldType.file, }, { name: 'price', label: 'Price', - type: ContentTypeType.file, + type: FieldType.file, }, ], }; diff --git a/api/src/cms/dto/contentType.dto.ts b/api/src/cms/dto/contentType.dto.ts index 33377af0..155e87ef 100644 --- a/api/src/cms/dto/contentType.dto.ts +++ b/api/src/cms/dto/contentType.dto.ts @@ -19,12 +19,12 @@ import { ValidateNested, } from 'class-validator'; -import { ContentTypeType } from '@/setting/schemas/types'; +import { FieldType } from '@/setting/schemas/types'; import { DtoConfig } from '@/utils/types/dto.types'; import { ValidateRequiredFields } from '../validators/validate-required-fields.validator'; -export class FieldType { +export class ContentField { @IsString() @IsNotEmpty() @Matches(/^[a-z][a-z_0-9]*$/) @@ -35,11 +35,11 @@ export class FieldType { label: string; @IsString() - @IsEnum(ContentTypeType, { + @IsEnum(FieldType, { message: "type must be one of the following values: 'text', 'url', 'textarea', 'checkbox', 'file', 'html'", }) - type: ContentTypeType; + type: FieldType; } export class ContentTypeCreateDto { @@ -48,13 +48,16 @@ export class ContentTypeCreateDto { @IsNotEmpty() name: string; - @ApiPropertyOptional({ description: 'Content type fields', type: FieldType }) + @ApiPropertyOptional({ + description: 'Content type fields', + type: ContentField, + }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Validate(ValidateRequiredFields) - @Type(() => FieldType) - fields?: FieldType[]; + @Type(() => ContentField) + fields?: ContentField[]; } export class ContentTypeUpdateDto extends PartialType(ContentTypeCreateDto) {} diff --git a/api/src/cms/schemas/content-type.schema.ts b/api/src/cms/schemas/content-type.schema.ts index 43970bfb..40fba159 100644 --- a/api/src/cms/schemas/content-type.schema.ts +++ b/api/src/cms/schemas/content-type.schema.ts @@ -12,7 +12,7 @@ import mongoose from 'mongoose'; import { BaseSchema } from '@/utils/generics/base-schema'; import { LifecycleHookManager } from '@/utils/generics/lifecycle-hook-manager'; -import { FieldType } from '../dto/contentType.dto'; +import { ContentField } from '../dto/contentType.dto'; @Schema({ timestamps: true }) export class ContentType extends BaseSchema { @@ -41,7 +41,7 @@ export class ContentType extends BaseSchema { }, ], }) - fields: FieldType[]; + fields: ContentField[]; } export const ContentTypeModel: ModelDefinition = LifecycleHookManager.attach({ diff --git a/api/src/cms/validators/validate-required-fields.validator.ts b/api/src/cms/validators/validate-required-fields.validator.ts index 75c372c9..64fe33ae 100644 --- a/api/src/cms/validators/validate-required-fields.validator.ts +++ b/api/src/cms/validators/validate-required-fields.validator.ts @@ -12,26 +12,26 @@ import { ValidatorConstraintInterface, } from 'class-validator'; -import { ContentTypeType } from '@/setting/schemas/types'; +import { FieldType } from '@/setting/schemas/types'; -import { FieldType } from '../dto/contentType.dto'; +import { ContentField } from '../dto/contentType.dto'; @ValidatorConstraint({ name: 'validateRequiredFields', async: false }) export class ValidateRequiredFields implements ValidatorConstraintInterface { - private readonly REQUIRED_FIELDS: FieldType[] = [ + private readonly REQUIRED_FIELDS: ContentField[] = [ { name: 'title', label: 'Title', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'status', label: 'Status', - type: ContentTypeType.checkbox, + type: FieldType.checkbox, }, ]; - validate(fields: FieldType[]): boolean { + validate(fields: ContentField[]): boolean { const errors: string[] = []; this.REQUIRED_FIELDS.forEach((requiredField, index) => { diff --git a/api/src/setting/schemas/types.ts b/api/src/setting/schemas/types.ts index 4de39331..f53aa8d8 100644 --- a/api/src/setting/schemas/types.ts +++ b/api/src/setting/schemas/types.ts @@ -20,7 +20,7 @@ export enum SettingType { multiple_attachment = 'multiple_attachment', } -export enum ContentTypeType { +export enum FieldType { text = 'text', url = 'url', textarea = 'textarea', diff --git a/api/src/utils/test/fixtures/contenttype.ts b/api/src/utils/test/fixtures/contenttype.ts index 577c8c6a..016bc323 100644 --- a/api/src/utils/test/fixtures/contenttype.ts +++ b/api/src/utils/test/fixtures/contenttype.ts @@ -13,7 +13,7 @@ import { ContentType, ContentTypeModel, } from '@/cms/schemas/content-type.schema'; -import { ContentTypeType } from '@/setting/schemas/types'; +import { FieldType } from '@/setting/schemas/types'; import { getFixturesWithDefaultValues } from '../defaultValues'; import { FixturesTypeBuilder } from '../types'; @@ -28,12 +28,12 @@ export const contentTypeDefaultValues: TContentTypeFixtures['defaultValues'] = { { name: 'title', label: 'Title', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'status', label: 'Status', - type: ContentTypeType.checkbox, + type: FieldType.checkbox, }, ], }; @@ -45,27 +45,27 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'status', label: 'Status', - type: ContentTypeType.checkbox, + type: FieldType.checkbox, }, { name: 'description', label: 'Description', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'image', label: 'Image', - type: ContentTypeType.file, + type: FieldType.file, }, { name: 'subtitle', label: 'Image', - type: ContentTypeType.file, + type: FieldType.file, }, ], }, @@ -75,22 +75,22 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'status', label: 'Status', - type: ContentTypeType.checkbox, + type: FieldType.checkbox, }, { name: 'address', label: 'Address', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'image', label: 'Image', - type: ContentTypeType.file, + type: FieldType.file, }, ], }, @@ -100,22 +100,22 @@ const contentTypes: TContentTypeFixtures['values'][] = [ { name: 'title', label: 'Title', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'status', label: 'Status', - type: ContentTypeType.checkbox, + type: FieldType.checkbox, }, { name: 'address', label: 'Address', - type: ContentTypeType.text, + type: FieldType.text, }, { name: 'image', label: 'Image', - type: ContentTypeType.file, + type: FieldType.file, }, ], }, From caaee58072e9b4cb0d1c5f5634a2bd5f151ae351 Mon Sep 17 00:00:00 2001 From: hexastack Date: Mon, 7 Apr 2025 15:15:10 +0100 Subject: [PATCH 4/5] fix: add suggestion --- api/src/cms/dto/contentType.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/api/src/cms/dto/contentType.dto.ts b/api/src/cms/dto/contentType.dto.ts index 155e87ef..bd6e5f0f 100644 --- a/api/src/cms/dto/contentType.dto.ts +++ b/api/src/cms/dto/contentType.dto.ts @@ -35,6 +35,7 @@ export class ContentField { label: string; @IsString() + @IsNotEmpty() @IsEnum(FieldType, { message: "type must be one of the following values: 'text', 'url', 'textarea', 'checkbox', 'file', 'html'", From e6ad44784b5fe77158beb49a18ff673a419a2c08 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Fri, 11 Apr 2025 23:57:47 +0100 Subject: [PATCH 5/5] fix: apply feedback update --- api/src/cms/schemas/content-type.schema.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/src/cms/schemas/content-type.schema.ts b/api/src/cms/schemas/content-type.schema.ts index 40fba159..6b6b3e43 100644 --- a/api/src/cms/schemas/content-type.schema.ts +++ b/api/src/cms/schemas/content-type.schema.ts @@ -9,6 +9,7 @@ import { ModelDefinition, Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import mongoose from 'mongoose'; +import { FieldType } from '@/setting/schemas/types'; import { BaseSchema } from '@/utils/generics/base-schema'; import { LifecycleHookManager } from '@/utils/generics/lifecycle-hook-manager'; @@ -32,12 +33,12 @@ export class ContentType extends BaseSchema { { name: 'title', label: 'Title', - type: 'text', + type: FieldType.text, }, { name: 'status', label: 'Status', - type: 'checkbox', + type: FieldType.checkbox, }, ], })