Преглед на файлове

fix(core): Correctly handle slug validation of deleted translations

Fixes #1527
Michael Bromley преди 3 години
родител
ревизия
61de8575c7
променени са 2 файла, в които са добавени 37 реда и са изтрити 7 реда
  1. 22 0
      packages/core/e2e/product.e2e-spec.ts
  2. 15 7
      packages/core/src/service/helpers/slug-validator/slug-validator.ts

+ 22 - 0
packages/core/e2e/product.e2e-spec.ts

@@ -1858,6 +1858,28 @@ describe('Product resolver', () => {
             expect(result.createProduct.slug).toBe(productToDelete.slug);
         });
 
+        // https://github.com/vendure-ecommerce/vendure/issues/1505
+        it('attempting to re-use deleted slug twice is not allowed', async () => {
+            const result = await adminClient.query<CreateProduct.Mutation, CreateProduct.Variables>(
+                CREATE_PRODUCT,
+                {
+                    input: {
+                        translations: [
+                            {
+                                languageCode: LanguageCode.en,
+                                name: 'Product reusing deleted slug',
+                                slug: productToDelete.slug,
+                                description: 'stuff',
+                            },
+                        ],
+                    },
+                },
+            );
+
+            expect(result.createProduct.slug).not.toBe(productToDelete.slug);
+            expect(result.createProduct.slug).toBe('laptop-2');
+        });
+
         // https://github.com/vendure-ecommerce/vendure/issues/800
         it('product can be fetched by slug of a deleted product', async () => {
             const { product } = await adminClient.query<GetProductSimple.Query, GetProductSimple.Variables>(

+ 15 - 7
packages/core/src/service/helpers/slug-validator/slug-validator.ts

@@ -43,6 +43,7 @@ export class SlugValidator {
                     t.slug = normalizeString(t.slug, '-');
                     let match: E | undefined;
                     let suffix = 1;
+                    const seen: ID[] = [];
                     const alreadySuffixed = /-\d+$/;
                     do {
                         const qb = this.connection
@@ -52,20 +53,27 @@ export class SlugValidator {
                             .where(`translation.slug = :slug`, { slug: t.slug })
                             .andWhere(`translation.languageCode = :languageCode`, {
                                 languageCode: t.languageCode,
-                            });
+                            })
                         if (input.id) {
                             qb.andWhere(`translation.base != :id`, { id: input.id });
                         }
+                        if (seen.length) {
+                            qb.andWhere(`translation.id NOT IN (:...seen)`, { seen });
+                        }
                         match = await qb.getOne();
-                        if (match && !match.base.deletedAt) {
-                            suffix++;
-                            if (alreadySuffixed.test(t.slug)) {
-                                t.slug = t.slug.replace(alreadySuffixed, `-${suffix}`);
+                        if (match) {
+                            if (!match.base.deletedAt) {
+                                suffix++;
+                                if (alreadySuffixed.test(t.slug)) {
+                                    t.slug = t.slug.replace(alreadySuffixed, `-${suffix}`);
+                                } else {
+                                    t.slug = `${t.slug}-${suffix}`;
+                                }
                             } else {
-                                t.slug = `${t.slug}-${suffix}`;
+                                seen.push(match.id);
                             }
                         }
-                    } while (match && !match.base.deletedAt);
+                    } while (match);
                 }
             }
         }