Browse Source

fix(core): Validate availableLanguages when update GlobalSettings

Michael Bromley 5 years ago
parent
commit
e304ae275c

+ 14 - 0
packages/core/e2e/channel.e2e-spec.ts

@@ -389,6 +389,20 @@ describe('Channels', () => {
 
             expect(updateChannel.defaultLanguageCode).toBe(LanguageCode.zh);
         });
+
+        it(
+            'attempting to remove availableLanguage when used by a Channel throws',
+            assertThrowsWithMessage(async () => {
+                await adminClient.query<UpdateGlobalSettings.Mutation, UpdateGlobalSettings.Variables>(
+                    UPDATE_GLOBAL_SETTINGS,
+                    {
+                        input: {
+                            availableLanguages: [LanguageCode.en],
+                        },
+                    },
+                );
+            }, 'Cannot remove make language "zh" unavailable as it is used as the defaultLanguage by the channel "__default_channel__"'),
+        );
     });
 
     it('deleteChannel', async () => {

+ 23 - 3
packages/core/src/api/resolvers/admin/global-settings.resolver.ts

@@ -1,15 +1,20 @@
 import { Args, Mutation, Query, ResolveField, Resolver } from '@nestjs/graphql';
 import { MutationUpdateGlobalSettingsArgs, Permission } from '@vendure/common/lib/generated-types';
 
-import { VendureConfig } from '../../../config';
+import { UserInputError } from '../../../common/error/errors';
 import { ConfigService } from '../../../config/config.service';
 import { CustomFields } from '../../../config/custom-field/custom-field-types';
+import { ChannelService } from '../../../service/services/channel.service';
 import { GlobalSettingsService } from '../../../service/services/global-settings.service';
 import { Allow } from '../../decorators/allow.decorator';
 
 @Resolver('GlobalSettings')
 export class GlobalSettingsResolver {
-    constructor(private configService: ConfigService, private globalSettingsService: GlobalSettingsService) {}
+    constructor(
+        private configService: ConfigService,
+        private globalSettingsService: GlobalSettingsService,
+        private channelService: ChannelService,
+    ) {}
 
     @Query()
     @Allow(Permission.Authenticated)
@@ -26,7 +31,7 @@ export class GlobalSettingsResolver {
         const exposedCustomFieldConfig: CustomFields = {};
         for (const [entityType, customFields] of Object.entries(this.configService.customFields)) {
             exposedCustomFieldConfig[entityType as keyof CustomFields] = customFields.filter(
-                c => !c.internal,
+                (c) => !c.internal,
             );
         }
         return {
@@ -37,6 +42,21 @@ export class GlobalSettingsResolver {
     @Mutation()
     @Allow(Permission.UpdateSettings)
     async updateGlobalSettings(@Args() args: MutationUpdateGlobalSettingsArgs) {
+        // This validation is performed here in the resolver rather than at the service
+        // layer to avoid a circular dependency [ChannelService <> GlobalSettingsService]
+        const { availableLanguages } = args.input;
+        if (availableLanguages) {
+            const channels = await this.channelService.findAll();
+            const unavailableDefaults = channels.filter(
+                (c) => !availableLanguages.includes(c.defaultLanguageCode),
+            );
+            if (unavailableDefaults.length) {
+                throw new UserInputError('error.cannot-set-default-language-as-unavailable', {
+                    language: unavailableDefaults.map((c) => c.defaultLanguageCode).join(', '),
+                    channelCode: unavailableDefaults.map((c) => c.code).join(', '),
+                });
+            }
+        }
         return this.globalSettingsService.updateSettings(args.input);
     }
 }

+ 1 - 0
packages/core/src/i18n/messages/en.json

@@ -9,6 +9,7 @@
     "cannot-move-collection-into-self": "Cannot move a Collection into itself",
     "cannot-remove-option-group-due-to-variants": "Cannot remove ProductOptionGroup \"{ code }\" as it is used by {count, plural, one {1 ProductVariant} other {# ProductVariants}}",
     "cannot-remove-tax-category-due-to-tax-rates": "Cannot remove TaxCategory \"{ name }\" as it is referenced by {count, plural, one {1 TaxRate} other {# TaxRates}}",
+    "cannot-set-default-language-as-unavailable": "Cannot remove make language \"{ language }\" unavailable as it is used as the defaultLanguage by the channel \"{channelCode}\"",
     "cannot-transition-order-from-to": "Cannot transition Order from \"{ fromState }\" to \"{ toState }\"",
     "cannot-transition-payment-from-to": "Cannot transition Payment from \"{ fromState }\" to \"{ toState }\"",
     "cannot-transition-refund-from-to": "Cannot transition Refund from \"{ fromState }\" to \"{ toState }\"",