Browse Source

fix(core): Do not return private collections in Shop API

Fixes #928
Michael Bromley 4 years ago
parent
commit
33f40f2a9c

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

@@ -6534,6 +6534,17 @@ export type GetProductCollectionQueryVariables = Exact<{ [key: string]: never; }
 
 
 export type GetProductCollectionQuery = { product?: Maybe<{ collections: Array<Pick<Collection, 'id' | 'name'>> }> };
 export type GetProductCollectionQuery = { product?: Maybe<{ collections: Array<Pick<Collection, 'id' | 'name'>> }> };
 
 
+export type GetCollectionShopQueryVariables = Exact<{
+  id?: Maybe<Scalars['ID']>;
+  slug?: Maybe<Scalars['String']>;
+}>;
+
+
+export type GetCollectionShopQuery = { collection?: Maybe<(
+    Pick<Collection, 'id' | 'name' | 'slug' | 'description'>
+    & { parent?: Maybe<Pick<Collection, 'id' | 'name'>>, children?: Maybe<Array<Pick<Collection, 'id' | 'name'>>> }
+  )> };
+
 export type DisableProductMutationVariables = Exact<{
 export type DisableProductMutationVariables = Exact<{
   id: Scalars['ID'];
   id: Scalars['ID'];
 }>;
 }>;
@@ -8276,6 +8287,14 @@ export namespace GetProductCollection {
   export type Collections = NonNullable<(NonNullable<(NonNullable<GetProductCollectionQuery['product']>)['collections']>)[number]>;
   export type Collections = NonNullable<(NonNullable<(NonNullable<GetProductCollectionQuery['product']>)['collections']>)[number]>;
 }
 }
 
 
+export namespace GetCollectionShop {
+  export type Variables = GetCollectionShopQueryVariables;
+  export type Query = GetCollectionShopQuery;
+  export type Collection = (NonNullable<GetCollectionShopQuery['collection']>);
+  export type Parent = (NonNullable<(NonNullable<GetCollectionShopQuery['collection']>)['parent']>);
+  export type Children = NonNullable<(NonNullable<(NonNullable<GetCollectionShopQuery['collection']>)['children']>)[number]>;
+}
+
 export namespace DisableProduct {
 export namespace DisableProduct {
   export type Variables = DisableProductMutationVariables;
   export type Variables = DisableProductMutationVariables;
   export type Mutation = DisableProductMutation;
   export type Mutation = DisableProductMutation;

+ 69 - 0
packages/core/e2e/shop-catalog.e2e-spec.ts

@@ -12,6 +12,7 @@ import {
     CreateFacet,
     CreateFacet,
     DisableProduct,
     DisableProduct,
     FacetWithValues,
     FacetWithValues,
+    GetCollection,
     GetCollectionList,
     GetCollectionList,
     GetCollectionVariants,
     GetCollectionVariants,
     GetFacetList,
     GetFacetList,
@@ -232,6 +233,27 @@ describe('Shop catalog', () => {
     describe('collections', () => {
     describe('collections', () => {
         let collection: CreateCollection.CreateCollection;
         let collection: CreateCollection.CreateCollection;
 
 
+        async function createNewCollection(name: string, isPrivate: boolean, parentId?: string) {
+            return await adminClient.query<CreateCollection.Mutation, CreateCollection.Variables>(
+                CREATE_COLLECTION,
+                {
+                    input: {
+                        translations: [
+                            {
+                                languageCode: LanguageCode.en,
+                                name,
+                                description: '',
+                                slug: name,
+                            },
+                        ],
+                        isPrivate,
+                        parentId,
+                        filters: [],
+                    },
+                },
+            );
+        }
+
         beforeAll(async () => {
         beforeAll(async () => {
             const result = await adminClient.query<GetFacetList.Query>(GET_FACET_LIST);
             const result = await adminClient.query<GetFacetList.Query>(GET_FACET_LIST);
             const category = result.facets.items[0];
             const category = result.facets.items[0];
@@ -387,9 +409,56 @@ describe('Shop catalog', () => {
 
 
             expect(result.product!.collections).toEqual([]);
             expect(result.product!.collections).toEqual([]);
         });
         });
+
+        it('private children not returned in Shop API', async () => {
+            const { createCollection: parent } = await createNewCollection('public-parent', false);
+            const { createCollection: child } = await createNewCollection('private-child', true, parent.id);
+
+            const result = await shopClient.query<GetCollection.Query, GetCollection.Variables>(
+                GET_COLLECTION_SHOP,
+                {
+                    id: parent.id,
+                },
+            );
+
+            expect(result.collection?.children).toEqual([]);
+        });
+
+        it('private parent not returned in Shop API', async () => {
+            const { createCollection: parent } = await createNewCollection('private-parent', true);
+            const { createCollection: child } = await createNewCollection('public-child', false, parent.id);
+
+            const result = await shopClient.query<GetCollection.Query, GetCollection.Variables>(
+                GET_COLLECTION_SHOP,
+                {
+                    id: child.id,
+                },
+            );
+
+            expect(result.collection?.parent).toBeNull();
+        });
     });
     });
 });
 });
 
 
+const GET_COLLECTION_SHOP = gql`
+    query GetCollectionShop($id: ID, $slug: String) {
+        collection(id: $id, slug: $slug) {
+            id
+            name
+            slug
+            description
+            parent {
+                id
+                name
+            }
+            children {
+                id
+                name
+            }
+        }
+    }
+`;
+
 const DISABLE_PRODUCT = gql`
 const DISABLE_PRODUCT = gql`
     mutation DisableProduct($id: ID!) {
     mutation DisableProduct($id: ID!) {
         updateProduct(input: { id: $id, enabled: false }) {
         updateProduct(input: { id: $id, enabled: false }) {

+ 20 - 6
packages/core/src/api/resolvers/entity/collection-entity.resolver.ts

@@ -67,19 +67,33 @@ export class CollectionEntityResolver {
     }
     }
 
 
     @ResolveField()
     @ResolveField()
-    async parent(@Ctx() ctx: RequestContext, @Parent() collection: Collection): Promise<Collection> {
+    async parent(
+        @Ctx() ctx: RequestContext,
+        @Parent() collection: Collection,
+        @Api() apiType: ApiType,
+    ): Promise<Collection | undefined> {
+        let parent: Collection;
         if (collection.parent) {
         if (collection.parent) {
-            return collection.parent;
+            parent = collection.parent;
+        } else {
+            parent = (await this.collectionService.getParent(ctx, collection.id)) as any;
         }
         }
-        return this.collectionService.getParent(ctx, collection.id) as any;
+        return apiType === 'shop' && parent.isPrivate ? undefined : parent;
     }
     }
 
 
     @ResolveField()
     @ResolveField()
-    async children(@Ctx() ctx: RequestContext, @Parent() collection: Collection): Promise<Collection[]> {
+    async children(
+        @Ctx() ctx: RequestContext,
+        @Parent() collection: Collection,
+        @Api() apiType: ApiType,
+    ): Promise<Collection[]> {
+        let children: Collection[] = [];
         if (collection.children) {
         if (collection.children) {
-            return collection.children;
+            children = collection.children;
+        } else {
+            children = (await this.collectionService.getChildren(ctx, collection.id)) as any;
         }
         }
-        return this.collectionService.getChildren(ctx, collection.id) as any;
+        return children.filter(c => (apiType === 'shop' ? !c.isPrivate : true));
     }
     }
 
 
     @ResolveField()
     @ResolveField()