From b4307c2ddb4d0bc282a6b070d56e16ff131f04c1 Mon Sep 17 00:00:00 2001 From: Harminder Virk Date: Mon, 13 May 2024 20:57:14 +0530 Subject: [PATCH] feat: move handle validation to product updation --- ...malize-handle.spec.ts => to-handle.spec.ts} | 4 ++-- packages/core/utils/src/common/index.ts | 2 +- .../{normalize-handle.ts => to-handle.ts} | 6 +++--- .../src/api-v2/admin/collections/validators.ts | 5 ++--- .../src/api-v2/admin/products/validators.ts | 7 ++----- .../api-v2/utils/common-validators/common.ts | 8 -------- packages/modules/product/src/models/product.ts | 4 ++-- .../src/services/product-module-service.ts | 18 +++++++++++++++--- 8 files changed, 27 insertions(+), 27 deletions(-) rename packages/core/utils/src/common/__tests__/{normalize-handle.spec.ts => to-handle.spec.ts} (86%) rename packages/core/utils/src/common/{normalize-handle.ts => to-handle.ts} (73%) diff --git a/packages/core/utils/src/common/__tests__/normalize-handle.spec.ts b/packages/core/utils/src/common/__tests__/to-handle.spec.ts similarity index 86% rename from packages/core/utils/src/common/__tests__/normalize-handle.spec.ts rename to packages/core/utils/src/common/__tests__/to-handle.spec.ts index b5293ccd67b1c..ddc18692475a5 100644 --- a/packages/core/utils/src/common/__tests__/normalize-handle.spec.ts +++ b/packages/core/utils/src/common/__tests__/to-handle.spec.ts @@ -1,4 +1,4 @@ -import { normalizeHandle } from "../normalize-handle" +import { toHandle } from "../to-handle" describe("normalizeHandle", function () { it("should generate URL friendly handles", function () { @@ -38,7 +38,7 @@ describe("normalizeHandle", function () { ] expectations.forEach((expectation) => { - expect(normalizeHandle(expectation.input)).toEqual(expectation.output) + expect(toHandle(expectation.input)).toEqual(expectation.output) }) }) }) diff --git a/packages/core/utils/src/common/index.ts b/packages/core/utils/src/common/index.ts index 9bbd3cafa3306..4fc71a54c15ac 100644 --- a/packages/core/utils/src/common/index.ts +++ b/packages/core/utils/src/common/index.ts @@ -58,5 +58,5 @@ export * from "./transaction" export * from "./trim-zeros" export * from "./upper-case-first" export * from "./wrap-handler" -export * from "./normalize-handle" +export * from "./to-handle" export * from "./validate-handle" diff --git a/packages/core/utils/src/common/normalize-handle.ts b/packages/core/utils/src/common/to-handle.ts similarity index 73% rename from packages/core/utils/src/common/normalize-handle.ts rename to packages/core/utils/src/common/to-handle.ts index 304aa788864e9..56800cd2c43c1 100644 --- a/packages/core/utils/src/common/normalize-handle.ts +++ b/packages/core/utils/src/common/to-handle.ts @@ -1,14 +1,14 @@ import { kebabCase } from "./to-kebab-case" /** - * Helper method to normalize entity "handle" to be URL - * friendly. + * Helper method to create a to be URL friendly "handle" from + * a string value. * * - Works by converting the value to lowercase * - Splits and remove accents from characters * - Removes all unallowed characters like a '"%$ and so on. */ -export const normalizeHandle = (value: string): string => { +export const toHandle = (value: string): string => { return kebabCase( value .toLowerCase() diff --git a/packages/medusa/src/api-v2/admin/collections/validators.ts b/packages/medusa/src/api-v2/admin/collections/validators.ts index 6088451f0fb17..687d6e8a1c04a 100644 --- a/packages/medusa/src/api-v2/admin/collections/validators.ts +++ b/packages/medusa/src/api-v2/admin/collections/validators.ts @@ -1,4 +1,3 @@ -import { HandleValidator } from "../../utils/common-validators" import { createFindParams, createOperatorMap, @@ -30,13 +29,13 @@ export const AdminGetCollectionsParams = createFindParams({ export type AdminCreateCollectionType = z.infer export const AdminCreateCollection = z.object({ title: z.string(), - handle: HandleValidator, + handle: z.string().optional(), metadata: z.record(z.unknown()).optional(), }) export type AdminUpdateCollectionType = z.infer export const AdminUpdateCollection = z.object({ title: z.string().optional(), - handle: HandleValidator, + handle: z.string().optional(), metadata: z.record(z.unknown()).optional(), }) diff --git a/packages/medusa/src/api-v2/admin/products/validators.ts b/packages/medusa/src/api-v2/admin/products/validators.ts index ce0de0c19fdec..4310de1c02655 100644 --- a/packages/medusa/src/api-v2/admin/products/validators.ts +++ b/packages/medusa/src/api-v2/admin/products/validators.ts @@ -1,9 +1,6 @@ import { ProductStatus } from "@medusajs/utils" import { z } from "zod" -import { - GetProductsParams, - HandleValidator, -} from "../../utils/common-validators" +import { GetProductsParams } from "../../utils/common-validators" import { createFindParams, createOperatorMap, @@ -182,7 +179,7 @@ export const AdminCreateProduct = z discountable: z.boolean().optional().default(true), images: z.array(z.object({ url: z.string() })).optional(), thumbnail: z.string().optional(), - handle: HandleValidator, + handle: z.string().optional(), status: statusEnum.optional().default(ProductStatus.DRAFT), type_id: z.string().nullable().optional(), collection_id: z.string().nullable().optional(), diff --git a/packages/medusa/src/api-v2/utils/common-validators/common.ts b/packages/medusa/src/api-v2/utils/common-validators/common.ts index 44c6f759513ef..7018683d2d67e 100644 --- a/packages/medusa/src/api-v2/utils/common-validators/common.ts +++ b/packages/medusa/src/api-v2/utils/common-validators/common.ts @@ -30,11 +30,3 @@ export const OptionalBooleanValidator = z.preprocess( (val: any) => optionalBooleanMapper.get(val?.toLowerCase()), z.boolean().optional() ) - -/** - * Validates entity handle to have URL-safe characters - */ -export const HandleValidator = z - .string() - .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/) - .optional() diff --git a/packages/modules/product/src/models/product.ts b/packages/modules/product/src/models/product.ts index 46e72ecf288d4..a6875141ef8bd 100644 --- a/packages/modules/product/src/models/product.ts +++ b/packages/modules/product/src/models/product.ts @@ -17,9 +17,9 @@ import { createPsqlIndexStatementHelper, DALUtils, generateEntityId, - kebabCase, ProductUtils, Searchable, + toHandle, } from "@medusajs/utils" import ProductCategory from "./product-category" import ProductCollection from "./product-collection" @@ -216,7 +216,7 @@ class Product { this.collection_id ??= this.collection?.id ?? null if (!this.handle && this.title) { - this.handle = kebabCase(this.title) + this.handle = toHandle(this.title) } } } diff --git a/packages/modules/product/src/services/product-module-service.ts b/packages/modules/product/src/services/product-module-service.ts index f7723e938d264..c904f26e43208 100644 --- a/packages/modules/product/src/services/product-module-service.ts +++ b/packages/modules/product/src/services/product-module-service.ts @@ -32,6 +32,7 @@ import { ProductStatus, promiseAll, removeUndefined, + isValidHandle, } from "@medusajs/utils" import { ProductCategoryEventData, @@ -1315,9 +1316,13 @@ export default class ProductModuleService< sharedContext )) as ProductTypes.CreateProductDTO - if (!productData.handle && productData.title) { - productData.handle = kebabCase(productData.title) - } + /** + * We are already computing handle from title in model. Do we + * need here again? + */ + // if (!productData.handle && productData.title) { + // productData.handle = kebabCase(productData.title) + // } if (!productData.status) { productData.status = ProductStatus.DRAFT @@ -1339,6 +1344,13 @@ export default class ProductModuleService< productData.discountable = false } + if (productData.handle && !isValidHandle(productData.handle)) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Invalid product handle. It must contain URL safe characters" + ) + } + if (productData.tags?.length && productData.tags.some((t) => !t.id)) { const dbTags = await this.productTagService_.list( {