Procházet zdrojové kódy

feat(core): Publish AssetEvent when Asset created/modified

Michael Bromley před 6 roky
rodič
revize
3a352c54e0

+ 6 - 4
packages/core/src/api/resolvers/admin/asset.resolver.ts

@@ -8,8 +8,10 @@ import {
 } from '@vendure/common/lib/generated-types';
 import { PaginatedList } from '@vendure/common/lib/shared-types';
 
+import { Ctx } from '../../../api/decorators/request-context.decorator';
 import { Asset } from '../../../entity/asset/asset.entity';
 import { AssetService } from '../../../service/services/asset.service';
+import { RequestContext } from '../../common/request-context';
 import { Allow } from '../../decorators/allow.decorator';
 
 @Resolver('Asset')
@@ -30,12 +32,12 @@ export class AssetResolver {
 
     @Mutation()
     @Allow(Permission.CreateCatalog)
-    async createAssets(@Args() args: MutationCreateAssetsArgs): Promise<Asset[]> {
+    async createAssets(@Ctx() ctx: RequestContext, @Args() args: MutationCreateAssetsArgs): Promise<Asset[]> {
         // TODO: Is there some way to parellelize this while still preserving
         // the order of files in the upload? Non-deterministic IDs mess up the e2e test snapshots.
         const assets: Asset[] = [];
         for (const input of args.input) {
-            const asset = await this.assetService.create(input);
+            const asset = await this.assetService.create(ctx, input);
             assets.push(asset);
         }
         return assets;
@@ -43,7 +45,7 @@ export class AssetResolver {
 
     @Mutation()
     @Allow(Permission.UpdateCatalog)
-    async updateAsset(@Args() { input }: MutationUpdateAssetArgs) {
-        return this.assetService.update(input);
+    async updateAsset(@Ctx() ctx: RequestContext, @Args() { input }: MutationUpdateAssetArgs) {
+        return this.assetService.update(ctx, input);
     }
 }

+ 21 - 0
packages/core/src/event-bus/events/asset-event.ts

@@ -0,0 +1,21 @@
+import { RequestContext } from '../../api/common/request-context';
+import { Asset } from '../../entity';
+import { VendureEvent } from '../vendure-event';
+
+/**
+ * @description
+ * This event is fired whenever aa {@link Asset} is added, updated
+ * or deleted.
+ *
+ * @docsCategory events
+ * @docsPage Event Types
+ */
+export class AssetEvent extends VendureEvent {
+    constructor(
+        public ctx: RequestContext,
+        public asset: Asset,
+        public type: 'created' | 'updated' | 'deleted',
+    ) {
+        super();
+    }
+}

+ 1 - 0
packages/core/src/event-bus/index.ts

@@ -3,6 +3,7 @@ export * from './event-bus.module';
 export * from './vendure-event';
 
 export * from './events/account-registration-event';
+export * from './events/asset-event';
 export * from './events/attempted-login-event';
 export * from './events/collection-modification-event';
 export * from './events/identifier-change-event';

+ 17 - 4
packages/core/src/service/services/asset.service.ts

@@ -9,6 +9,7 @@ import path from 'path';
 import { Stream } from 'stream';
 import { Connection, Like } from 'typeorm';
 
+import { RequestContext } from '../../api/common/request-context';
 import { InternalServerError, UserInputError } from '../../common/error/errors';
 import { ListQueryOptions } from '../../common/types/common-types';
 import { getAssetType, idsAreEqual } from '../../common/utils';
@@ -17,6 +18,8 @@ import { Logger } from '../../config/logger/vendure-logger';
 import { Asset } from '../../entity/asset/asset.entity';
 import { OrderableAsset } from '../../entity/asset/orderable-asset.entity';
 import { VendureEntity } from '../../entity/base/base.entity';
+import { EventBus } from '../../event-bus/event-bus';
+import { AssetEvent } from '../../event-bus/events/asset-event';
 import { ListQueryBuilder } from '../helpers/list-query-builder/list-query-builder';
 import { getEntityOrThrow } from '../helpers/utils/get-entity-or-throw';
 import { patchEntity } from '../helpers/utils/patch-entity';
@@ -39,6 +42,7 @@ export class AssetService {
         @InjectConnection() private connection: Connection,
         private configService: ConfigService,
         private listQueryBuilder: ListQueryBuilder,
+        private eventBus: EventBus,
     ) {}
 
     findOne(id: ID): Promise<Asset | undefined> {
@@ -133,16 +137,25 @@ export class AssetService {
     /**
      * Create an Asset based on a file uploaded via the GraphQL API.
      */
-    async create(input: CreateAssetInput): Promise<Asset> {
+    async create(ctx: RequestContext, input: CreateAssetInput): Promise<Asset> {
         const { createReadStream, filename, mimetype } = await input.file;
         const stream = createReadStream();
-        return this.createAssetInternal(stream, filename, mimetype);
+        const asset = await this.createAssetInternal(stream, filename, mimetype);
+        this.eventBus.publish(new AssetEvent(ctx, asset, 'created'));
+        return asset;
     }
 
-    async update(input: UpdateAssetInput): Promise<Asset> {
+    async update(ctx: RequestContext, input: UpdateAssetInput): Promise<Asset> {
         const asset = await getEntityOrThrow(this.connection, Asset, input.id);
+        if (input.focalPoint) {
+            const to3dp = (x: number) => +x.toFixed(3);
+            input.focalPoint.x = to3dp(input.focalPoint.x);
+            input.focalPoint.y = to3dp(input.focalPoint.y);
+        }
         patchEntity(asset, input);
-        return this.connection.getRepository(Asset).save(asset);
+        const updatedAsset = await this.connection.getRepository(Asset).save(asset);
+        this.eventBus.publish(new AssetEvent(ctx, updatedAsset, 'updated'));
+        return updatedAsset;
     }
 
     /**