1
0
Эх сурвалжийг харах

WIP encrypted custom fields

Exploring some ideas for #2648
Michael Bromley 1 жил өмнө
parent
commit
88e5140349

+ 2 - 0
packages/admin-ui/src/lib/react/src/public_api.ts

@@ -11,11 +11,13 @@ export * from './react-components/FormField';
 export * from './react-components/Link';
 export * from './react-components/PageBlock';
 export * from './react-components/PageDetailLayout';
+export * from './react-components/RichTextEditor';
 export * from './react-hooks/use-detail-component-data';
 export * from './react-hooks/use-form-control';
 export * from './react-hooks/use-injector';
 export * from './react-hooks/use-page-metadata';
 export * from './react-hooks/use-query';
+export * from './react-hooks/use-rich-text-editor';
 export * from './react-hooks/use-route-params';
 export * from './register-react-custom-detail-component';
 export * from './register-react-data-table-component';

+ 1 - 1
packages/core/src/bootstrap.ts

@@ -205,7 +205,7 @@ export async function preBootstrapConfig(
     }
 
     const entities = await getAllEntities(userConfig);
-    const { coreSubscribersMap } = await import('./entity/subscribers.js');
+    const { coreSubscribersMap } = await import('./connection/subscribers.js');
     await setConfig({
         dbConnectionOptions: {
             entities,

+ 3 - 1
packages/core/src/config/custom-field/custom-field-types.ts

@@ -91,7 +91,9 @@ export type TypedCustomFieldConfig<
 > = BaseTypedCustomFieldConfig<T, C> &
     (TypedCustomSingleFieldConfig<T, C> | TypedCustomListFieldConfig<T, C>);
 
-export type StringCustomFieldConfig = TypedCustomFieldConfig<'string', GraphQLStringCustomFieldConfig>;
+export type StringCustomFieldConfig = TypedCustomFieldConfig<'string', GraphQLStringCustomFieldConfig> & {
+    encryptionSecret?: string;
+};
 export type LocaleStringCustomFieldConfig = TypedCustomFieldConfig<
     'localeString',
     GraphQLLocaleStringCustomFieldConfig

+ 7 - 1
packages/core/src/connection/connection.module.ts

@@ -5,6 +5,7 @@ import { DataSourceOptions } from 'typeorm';
 import { ConfigModule } from '../config/config.module';
 import { ConfigService } from '../config/config.service';
 import { TypeOrmLogger } from '../config/logger/typeorm-logger';
+import { EncryptedCustomFieldSubscriber } from './subscribers';
 
 import { TransactionSubscriber } from './transaction-subscriber';
 import { TransactionWrapper } from './transaction-wrapper';
@@ -14,7 +15,12 @@ let defaultTypeOrmModule: DynamicModule;
 
 @Module({
     imports: [ConfigModule],
-    providers: [TransactionalConnection, TransactionSubscriber, TransactionWrapper],
+    providers: [
+        TransactionalConnection,
+        TransactionSubscriber,
+        TransactionWrapper,
+        EncryptedCustomFieldSubscriber,
+    ],
     exports: [TransactionalConnection, TransactionSubscriber, TransactionWrapper],
 })
 export class ConnectionModule {

+ 24 - 1
packages/core/src/entity/subscribers.ts → packages/core/src/connection/subscribers.ts

@@ -1,6 +1,8 @@
-import { EntitySubscriberInterface, EventSubscriber, InsertEvent } from 'typeorm';
+import { Injectable } from '@nestjs/common';
+import { EntitySubscriberInterface, EventSubscriber, InsertEvent, LoadEvent, UpdateEvent } from 'typeorm';
 
 import { CalculatedColumnDefinition, CALCULATED_PROPERTIES } from '../common/calculated-decorator';
+import { ConfigService } from '../config/index';
 
 interface EntityPrototype {
     [CALCULATED_PROPERTIES]: CalculatedColumnDefinition[];
@@ -47,9 +49,30 @@ export class CalculatedPropertySubscriber implements EntitySubscriberInterface {
     }
 }
 
+@Injectable()
+@EventSubscriber()
+export class EncryptedCustomFieldSubscriber implements EntitySubscriberInterface {
+    // constructor(private configService: ConfigService) {}
+
+    listenTo(): Function | string {}
+
+    afterLoad(entity: any, event?: LoadEvent<any>): Promise<any> | void {
+        // console.log(`afterLoad: ${entity}`);
+    }
+
+    beforeInsert(event: InsertEvent<any>): Promise<any> | void {
+        // console.log(`beforeInsert: ${event}`);
+    }
+
+    beforeUpdate(event: UpdateEvent<any>): Promise<any> | void {
+        // console.log(`beforeUpdate: ${event}`);
+    }
+}
+
 /**
  * A map of the core TypeORM Subscribers.
  */
 export const coreSubscribersMap = {
     CalculatedPropertySubscriber,
+    // EncryptedCustomFieldSubscriber,
 };

+ 1 - 1
packages/core/src/entity/base/base.entity.spec.ts

@@ -2,7 +2,7 @@ import { DeepPartial } from '@vendure/common/lib/shared-types';
 import { describe, expect, it } from 'vitest';
 
 import { Calculated } from '../../common/index';
-import { CalculatedPropertySubscriber } from '../subscribers';
+import { CalculatedPropertySubscriber } from '../../connection/subscribers';
 
 import { VendureEntity } from './base.entity';
 

+ 35 - 2
packages/core/src/entity/register-custom-entity-fields.ts

@@ -2,14 +2,19 @@
 import { CustomFieldType } from '@vendure/common/lib/shared-types';
 import { assertNever } from '@vendure/common/lib/shared-utils';
 import {
+    AfterLoad,
+    BeforeUpdate,
     Column,
     ColumnOptions,
     ColumnType,
     DataSourceOptions,
+    EntitySubscriberInterface,
+    EventSubscriber,
     getMetadataArgsStorage,
     Index,
     JoinColumn,
     JoinTable,
+    LoadEvent,
     ManyToMany,
     ManyToOne,
 } from 'typeorm';
@@ -19,6 +24,7 @@ import { DateUtils } from 'typeorm/util/DateUtils';
 import { CustomFieldConfig, CustomFields } from '../config/custom-field/custom-field-types';
 import { Logger } from '../config/logger/vendure-logger';
 import { VendureConfig } from '../config/vendure-config';
+import { VendureEntity } from './base/base.entity';
 
 /**
  * The maximum length of the "length" argument of a MySQL varchar column.
@@ -33,7 +39,8 @@ function registerCustomFieldsForEntity(
     entityName: keyof CustomFields,
     // eslint-disable-next-line @typescript-eslint/prefer-function-type
     ctor: { new (): any },
-    translation = false,
+    translation: boolean,
+    targetEntity: Function,
 ) {
     const customFields = config.customFields && config.customFields[entityName];
     const dbEngine = config.dbConnectionOptions.type;
@@ -102,6 +109,25 @@ function registerCustomFieldsForEntity(
                         // sufficient to add the `unique: true` property to the column options.
                         Index({ unique: true })(instance, name);
                     }
+                    if (customField.type === 'string' && customField.encryptionSecret) {
+                        @EventSubscriber()
+                        class DynamicSubscriber implements EntitySubscriberInterface {
+                            listenTo() {
+                                return targetEntity;
+                            }
+
+                            afterLoad(entity: any, event?: LoadEvent<any>): Promise<any> | void {}
+
+                            beforeInsert(event: any) {
+                                console.log(`beforeInsert: ${event}`);
+                            }
+                            beforeUpdate(event: any) {
+                                console.log(`beforeUpdate: ${event}`);
+                            }
+                        }
+
+                        (config.dbConnectionOptions.subscribers as any[]).push(DynamicSubscriber);
+                    }
                 }
             };
 
@@ -245,7 +271,13 @@ export function registerCustomEntityFields(config: VendureConfig) {
             const customFieldsMetadata = getCustomFieldsMetadata(entityName);
             const customFieldsClass = customFieldsMetadata.type();
             if (customFieldsClass && typeof customFieldsClass !== 'string') {
-                registerCustomFieldsForEntity(config, entityName, customFieldsClass as any);
+                registerCustomFieldsForEntity(
+                    config,
+                    entityName,
+                    customFieldsClass as any,
+                    false,
+                    customFieldsMetadata.target as Function,
+                );
             }
             const translationsMetadata = metadataArgsStorage
                 .filterRelations(customFieldsMetadata.target)
@@ -263,6 +295,7 @@ export function registerCustomEntityFields(config: VendureConfig) {
                         entityName,
                         customFieldsTranslationClass as any,
                         true,
+                        customFieldsMetadata.target as Function,
                     );
                 }
             } else {

+ 9 - 1
packages/dev-server/dev-config.ts

@@ -62,7 +62,15 @@ export const devConfig: VendureConfig = {
         paymentMethodHandlers: [dummyPaymentHandler],
     },
 
-    customFields: {},
+    customFields: {
+        Product: [
+            {
+                name: 'secret',
+                type: 'string',
+                encryptionSecret: 'foo',
+            },
+        ],
+    },
     logger: new DefaultLogger({ level: LogLevel.Verbose }),
     importExportOptions: {
         importAssetsDir: path.join(__dirname, 'import-assets'),