Kaynağa Gözat

feat(core): Expose RequestContextService and add `create()` method

Michael Bromley 3 yıl önce
ebeveyn
işleme
335dfb5b67

+ 0 - 2
packages/core/src/api/api.module.ts

@@ -10,7 +10,6 @@ import { I18nModule } from '../i18n/i18n.module';
 import { ServiceModule } from '../service/service.module';
 
 import { AdminApiModule, ApiSharedModule, ShopApiModule } from './api-internal-modules';
-import { RequestContextService } from './common/request-context.service';
 import { configureGraphQLModule } from './config/configure-graphql-module';
 import { AuthGuard } from './middleware/auth-guard';
 import { ExceptionLoggerFilter } from './middleware/exception-logger.filter';
@@ -52,7 +51,6 @@ import { ValidateCustomFieldsInterceptor } from './middleware/validate-custom-fi
         })),
     ],
     providers: [
-        RequestContextService,
         {
             provide: APP_GUARD,
             useClass: AuthGuard,

+ 3 - 1
packages/core/src/api/common/request-context.ts

@@ -79,7 +79,9 @@ export class RequestContext {
      * @description
      * Creates an "empty" RequestContext object. This is only intended to be used
      * when a service method must be called outside the normal request-response
-     * cycle, e.g. when programmatically populating data.
+     * cycle, e.g. when programmatically populating data. Usually a better alternative
+     * is to use the {@link RequestContextService} `create()` method, which allows more control
+     * over the resulting RequestContext object.
      */
     static empty(): RequestContext {
         return new RequestContext({

+ 1 - 1
packages/core/src/api/middleware/auth-guard.ts

@@ -10,13 +10,13 @@ import { ConfigService } from '../../config/config.service';
 import { LogLevel } from '../../config/logger/vendure-logger';
 import { CachedSession } from '../../config/session-cache/session-cache-strategy';
 import { Customer } from '../../entity/customer/customer.entity';
+import { RequestContextService } from '../../service/helpers/request-context/request-context.service';
 import { ChannelService } from '../../service/services/channel.service';
 import { CustomerService } from '../../service/services/customer.service';
 import { SessionService } from '../../service/services/session.service';
 import { extractSessionToken } from '../common/extract-session-token';
 import { parseContext } from '../common/parse-context';
 import { RequestContext } from '../common/request-context';
-import { RequestContextService } from '../common/request-context.service';
 import { setSessionToken } from '../common/set-session-token';
 import { PERMISSIONS_METADATA_KEY } from '../decorators/allow.decorator';
 

+ 73 - 10
packages/core/src/api/common/request-context.service.ts → packages/core/src/service/helpers/request-context/request-context.service.ts

@@ -1,26 +1,89 @@
 import { Injectable } from '@nestjs/common';
 import { LanguageCode, Permission } from '@vendure/common/lib/generated-types';
+import { ID } from '@vendure/common/lib/shared-types';
 import { Request } from 'express';
 import { GraphQLResolveInfo } from 'graphql';
+import ms from 'ms';
 
-import { idsAreEqual } from '../../common/utils';
-import { ConfigService } from '../../config/config.service';
-import { CachedSession, CachedSessionUser } from '../../config/session-cache/session-cache-strategy';
-import { Channel } from '../../entity/channel/channel.entity';
-import { ChannelService } from '../../service/services/channel.service';
-
-import { getApiType } from './get-api-type';
-import { RequestContext } from './request-context';
+import { ApiType, getApiType } from '../../../api/common/get-api-type';
+import { RequestContext } from '../../../api/common/request-context';
+import { idsAreEqual } from '../../../common/utils';
+import { ConfigService } from '../../../config/config.service';
+import { CachedSession, CachedSessionUser } from '../../../config/session-cache/session-cache-strategy';
+import { Channel } from '../../../entity/channel/channel.entity';
+import { User } from '../../../entity/index';
+import { ChannelService } from '../../services/channel.service';
+import { getUserChannelsPermissions } from '../utils/get-user-channels-permissions';
 
 /**
- * Creates new RequestContext instances.
+ * @description
+ * Creates new {@link RequestContext} instances.
+ *
+ * @docsCategory request
  */
 @Injectable()
 export class RequestContextService {
+    /** @internal */
     constructor(private channelService: ChannelService, private configService: ConfigService) {}
 
     /**
-     * Creates a new RequestContext based on an Express request object.
+     * @description
+     * Creates a RequestContext based on the config provided. This can be useful when interacting
+     * with services outside the request-response cycle, for example in stand-alone scripts or in
+     * worker jobs.
+     *
+     * @since 1.5.0
+     */
+    async create(config: {
+        req?: Request;
+        apiType: ApiType;
+        channelOrToken?: Channel | string;
+        languageCode?: LanguageCode;
+        user?: User;
+        activeOrderId?: ID;
+    }): Promise<RequestContext> {
+        const { req, apiType, channelOrToken, languageCode, user, activeOrderId } = config;
+        let channel: Channel;
+        if (channelOrToken instanceof Channel) {
+            channel = channelOrToken;
+        } else if (typeof channelOrToken === 'string') {
+            channel = await this.channelService.getChannelFromToken(channelOrToken);
+        } else {
+            channel = await this.channelService.getDefaultChannel();
+        }
+        let session: CachedSession | undefined;
+        if (user) {
+            const channelPermissions = user.roles ? getUserChannelsPermissions(user) : [];
+            session = {
+                user: {
+                    id: user.id,
+                    identifier: user.identifier,
+                    verified: user.verified,
+                    channelPermissions,
+                },
+                id: '__dummy_session_id__',
+                token: '__dummy_session_token__',
+                expires: new Date(Date.now() + ms('1y')),
+                cacheExpiry: ms('1y'),
+                activeOrderId,
+            };
+        }
+        return new RequestContext({
+            req,
+            apiType,
+            channel,
+            languageCode,
+            session,
+            isAuthorized: true,
+            authorizedAsOwnerOnly: false,
+        });
+    }
+
+    /**
+     * @description
+     * Creates a new RequestContext based on an Express request object. This is used internally
+     * in the API layer by the AuthGuard, and creates the RequestContext which is then passed
+     * to all resolvers & controllers.
      */
     async fromRequest(
         req: Request,

+ 2 - 0
packages/core/src/service/index.ts

@@ -13,6 +13,8 @@ export * from './helpers/order-state-machine/order-state';
 export * from './helpers/password-cipher/password-cipher';
 export * from './helpers/payment-state-machine/payment-state';
 export * from './helpers/product-price-applicator/product-price-applicator';
+export * from './helpers/refund-state-machine/refund-state';
+export * from './helpers/request-context/request-context.service';
 export * from './helpers/translatable-saver/translatable-saver';
 export * from './helpers/utils/patch-entity';
 export * from './helpers/utils/translate-entity';

+ 2 - 0
packages/core/src/service/service.module.ts

@@ -22,6 +22,7 @@ import { PasswordCipher } from './helpers/password-cipher/password-cipher';
 import { PaymentStateMachine } from './helpers/payment-state-machine/payment-state-machine';
 import { ProductPriceApplicator } from './helpers/product-price-applicator/product-price-applicator';
 import { RefundStateMachine } from './helpers/refund-state-machine/refund-state-machine';
+import { RequestContextService } from './helpers/request-context/request-context.service';
 import { ShippingCalculator } from './helpers/shipping-calculator/shipping-calculator';
 import { SlugValidator } from './helpers/slug-validator/slug-validator';
 import { TranslatableSaver } from './helpers/translatable-saver/translatable-saver';
@@ -116,6 +117,7 @@ const helpers = [
     ActiveOrderService,
     ProductPriceApplicator,
     EntityHydrator,
+    RequestContextService,
 ];
 
 /**