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

fix(core): Omit private facet values from Product.facetValues

Fixes #1435
Michael Bromley 3 жил өмнө
parent
commit
82e0b26e55

+ 2 - 2
packages/common/src/generated-shop-types.ts

@@ -1605,7 +1605,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2799,7 +2799,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevance score for the result. Differs between database implementations */
+    /** A relevence score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };
 

+ 68 - 0
packages/core/e2e/facet.e2e-spec.ts

@@ -21,6 +21,7 @@ import {
     GetFacetList,
     GetFacetWithValues,
     GetProductListWithVariants,
+    GetProductWithFacetValues,
     GetProductWithVariants,
     LanguageCode,
     UpdateFacet,
@@ -178,6 +179,52 @@ describe('Facet resolver', () => {
         expect(result.facet!.name).toBe('Speaker Category');
     });
 
+    it('product.facetValues resolver omits private facets in shop-api', async () => {
+        const publicFacetValue = brandFacet.values[0];
+        const privateFacetValue = speakerTypeFacet.values[0];
+        await adminClient.query<UpdateProduct.Mutation, UpdateProduct.Variables>(UPDATE_PRODUCT, {
+            input: {
+                id: 'T_1',
+                facetValueIds: [publicFacetValue.id, privateFacetValue.id],
+            },
+        });
+        const { product } = await shopClient.query<
+            GetProductWithFacetValues.Query,
+            GetProductWithFacetValues.Variables
+        >(GET_PRODUCT_WITH_FACET_VALUES, {
+            id: 'T_1',
+        });
+
+        expect(product?.facetValues.map(v => v.id).includes(publicFacetValue.id)).toBe(true);
+        expect(product?.facetValues.map(v => v.id).includes(privateFacetValue.id)).toBe(false);
+    });
+
+    it('productVariant.facetValues resolver omits private facets in shop-api', async () => {
+        const publicFacetValue = brandFacet.values[0];
+        const privateFacetValue = speakerTypeFacet.values[0];
+        await adminClient.query<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
+            UPDATE_PRODUCT_VARIANTS,
+            {
+                input: [
+                    {
+                        id: 'T_1',
+                        facetValueIds: [publicFacetValue.id, privateFacetValue.id],
+                    },
+                ],
+            },
+        );
+        const { product } = await shopClient.query<
+            GetProductWithFacetValues.Query,
+            GetProductWithFacetValues.Variables
+        >(GET_PRODUCT_WITH_FACET_VALUES, {
+            id: 'T_1',
+        });
+
+        const productVariant1 = product?.variants.find(v => v.id === 'T_1');
+        expect(productVariant1?.facetValues.map(v => v.id).includes(publicFacetValue.id)).toBe(true);
+        expect(productVariant1?.facetValues.map(v => v.id).includes(privateFacetValue.id)).toBe(false);
+    });
+
     describe('deletion', () => {
         let products: GetProductListWithVariants.Items[];
 
@@ -672,6 +719,27 @@ const DELETE_FACET = gql`
     }
 `;
 
+const GET_PRODUCT_WITH_FACET_VALUES = gql`
+    query GetProductWithFacetValues($id: ID!) {
+        product(id: $id) {
+            id
+            facetValues {
+                id
+                name
+                code
+            }
+            variants {
+                id
+                facetValues {
+                    id
+                    name
+                    code
+                }
+            }
+        }
+    }
+`;
+
 const GET_PRODUCTS_LIST_WITH_VARIANTS = gql`
     query GetProductListWithVariants {
         products {

+ 34 - 0
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -5436,6 +5436,21 @@ export type DeleteFacetMutationVariables = Exact<{
 
 export type DeleteFacetMutation = { deleteFacet: Pick<DeletionResponse, 'result' | 'message'> };
 
+export type GetProductWithFacetValuesQueryVariables = Exact<{
+    id: Scalars['ID'];
+}>;
+
+export type GetProductWithFacetValuesQuery = {
+    product?: Maybe<
+        Pick<Product, 'id'> & {
+            facetValues: Array<Pick<FacetValue, 'id' | 'name' | 'code'>>;
+            variants: Array<
+                Pick<ProductVariant, 'id'> & { facetValues: Array<Pick<FacetValue, 'id' | 'name' | 'code'>> }
+            >;
+        }
+    >;
+};
+
 export type GetProductListWithVariantsQueryVariables = Exact<{ [key: string]: never }>;
 
 export type GetProductListWithVariantsQuery = {
@@ -7778,6 +7793,25 @@ export namespace DeleteFacet {
     export type DeleteFacet = NonNullable<DeleteFacetMutation['deleteFacet']>;
 }
 
+export namespace GetProductWithFacetValues {
+    export type Variables = GetProductWithFacetValuesQueryVariables;
+    export type Query = GetProductWithFacetValuesQuery;
+    export type Product = NonNullable<GetProductWithFacetValuesQuery['product']>;
+    export type FacetValues = NonNullable<
+        NonNullable<NonNullable<GetProductWithFacetValuesQuery['product']>['facetValues']>[number]
+    >;
+    export type Variants = NonNullable<
+        NonNullable<NonNullable<GetProductWithFacetValuesQuery['product']>['variants']>[number]
+    >;
+    export type _FacetValues = NonNullable<
+        NonNullable<
+            NonNullable<
+                NonNullable<NonNullable<GetProductWithFacetValuesQuery['product']>['variants']>[number]
+            >['facetValues']
+        >[number]
+    >;
+}
+
 export namespace GetProductListWithVariants {
     export type Variables = GetProductListWithVariantsQueryVariables;
     export type Query = GetProductListWithVariantsQuery;

+ 3 - 5
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -1551,7 +1551,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2702,7 +2702,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevance score for the result. Differs between database implementations */
+    /** A relevence score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };
 
@@ -3439,9 +3439,7 @@ export type GetOrderByCodeWithPaymentsQueryVariables = Exact<{
 
 export type GetOrderByCodeWithPaymentsQuery = { orderByCode?: Maybe<TestOrderWithPaymentsFragment> };
 
-export type GetActiveCustomerOrderWithItemFulfillmentsQueryVariables = Exact<{
-    code: Scalars['String'];
-}>;
+export type GetActiveCustomerOrderWithItemFulfillmentsQueryVariables = Exact<{ [key: string]: never }>;
 
 export type GetActiveCustomerOrderWithItemFulfillmentsQuery = {
     activeCustomer?: Maybe<{

+ 10 - 1
packages/core/src/api/resolvers/entity/product-entity.resolver.ts

@@ -89,6 +89,7 @@ export class ProductEntityResolver {
     async facetValues(
         @Ctx() ctx: RequestContext,
         @Parent() product: Product,
+        @Api() apiType: ApiType,
     ): Promise<Array<Translated<FacetValue>>> {
         if (product.facetValues?.length === 0) {
             return [];
@@ -99,7 +100,15 @@ export class ProductEntityResolver {
         } else {
             facetValues = await this.productService.getFacetValuesForProduct(ctx, product.id);
         }
-        return facetValues.filter(fv => fv.channels.find(c => idsAreEqual(c.id, ctx.channelId)));
+        return facetValues.filter(fv => {
+            if (!fv.channels.find(c => idsAreEqual(c.id, ctx.channelId))) {
+                return false;
+            }
+            if (apiType === 'shop' && fv.facet.isPrivate) {
+                return false;
+            }
+            return true;
+        });
     }
 
     @ResolveField()

+ 2 - 2
packages/payments-plugin/e2e/graphql/generated-shop-types.ts

@@ -1551,7 +1551,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2702,7 +2702,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevance score for the result. Differs between database implementations */
+    /** A relevence score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };